0
$\begingroup$

Rosanswers logo

This is the situation:
Node A has a service client which calls a service server defined in node B for all the time.

In the meanwhile, node B also has a service client which calls a service server defined in node A for all the time.

In other words, there are a service client and server in node A, and there are also a service server and client in node B. And they call each other all the time.

Now comes the problem, the program hangs there and no call is successful. It seems there is a deadlock. Any one could give me a detailed explanation? And any one could provide me with a solution? Thanks!

Node A:

#include "ros/ros.h"
#include "roscpp_tutorials/TwoInts.h"
#include <cstdlib>

bool test(roscpp_tutorials::TwoInts::Request  &req,
         roscpp_tutorials::TwoInts::Response &res )
{
  res.sum = req.a + req.b;
  ROS_INFO("test : x=%ld, y=%ld", (long int)req.a, (long int)req.b);
  ROS_INFO(" test sending back response: [%ld]", (long int)res.sum);
  return true;
}

int main(int argc, char **argv)
{
    ros::init(argc, argv, "add_two_ints_client");
    ros::NodeHandle n;

    ros::ServiceClient client = n.serviceClient<roscpp_tutorials::TwoInts>("add_two_ints");
    ros::ServiceServer server = n.advertiseService("test", test);

    ros::Rate rate(10);

    roscpp_tutorials::TwoInts srv;
    srv.request.a = 1;
    srv.request.b = 2;

    while(ros::ok())
    {
        if (client.call(srv))
        {
          ROS_INFO("Sum: %ld", (long int)srv.response.sum);
        }
        else
        {
          ROS_ERROR("Failed to call service add_two_ints");
        }
        ros::spinOnce();
        rate.sleep();
    }

    return 0;
}

Node B:

#include "ros/ros.h"
#include "roscpp_tutorials/TwoInts.h"

bool add(roscpp_tutorials::TwoInts::Request  &req,
         roscpp_tutorials::TwoInts::Response &res )
{
  res.sum = req.a + req.b;
  ROS_INFO("request: x=%ld, y=%ld", (long int)req.a, (long int)req.b);
  ROS_INFO("  sending back response: [%ld]", (long int)res.sum);
  return true;
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, "add_two_ints_server");
  ros::NodeHandle n;

  ros::ServiceServer service = n.advertiseService("add_two_ints", add);
  ros::ServiceClient client = n.serviceClient<roscpp_tutorials::TwoInts>("test");

  ros::Rate rate(10);

  roscpp_tutorials::TwoInts srv;
  srv.request.a = 1;
  srv.request.b = 2;

  while(ros::ok())
  {
      if (client.call(srv))
      {
        ROS_INFO("test: %ld", (long int)srv.response.sum);
      }
      else
      {
        ROS_ERROR("Failed to call service test");
      }
      ros::spinOnce();
      rate.sleep();
  }
  //ros::spin();

  return 0;
}

Originally posted by Winston on ROS Answers with karma: 180 on 2016-08-28

Post score: 0

$\endgroup$

1 Answer 1

0
$\begingroup$

Rosanswers logo

Yep, definitely looks like you've created a deadlock.

By default, roscpp runs in a single thread and processes your service callbacks as part of ros::spinOnce() (or ros::spin()). Since service calls are blocking, when each program starts the service call it can't execute callbacks until the service call completes.

Both of your programs are probably sitting at client.call(), waiting for the other program to process its service callback.

There are a couple of ways to solve this:

  • Re-design your program so that it doesn't have a deadlock. (I would start by asking whether you really need blocking service calls; can you use topics instead?)
  • Use an AyncSpinner or some other mechanism to process callbacks in a different thread

Originally posted by ahendrix with karma: 47576 on 2016-08-28

This answer was ACCEPTED on the original site

Post score: 1


Original comments

Comment by Winston on 2016-08-29:
I want to guarantee that the client's EVERY message/call would be received by the server but it seems that topics could not guarantee that. I won't use ros service if topics could meet my requirement. @ahendrix

Comment by ahendrix on 2016-08-29:
If you really need to guarantee delivery of EVERY message, then services may be the only answer. However, most of the users I find who say this don't actually need it; a slight change to the message semantics might be tolerant to dropped messages.

Comment by Winston on 2016-08-31:
Thank you! I would like to how how to change the message's semantics to be tolerant to dropped messages. Could you give me some advice?

Comment by ahendrix on 2016-08-31:
I have no idea. They're your messages and your requirement for no dropped messages. If you want advice about specific messages and a specific application, I suggest you open a new question that describes your application and your messages and asks how to make it more tolerant to dropped messages.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.