Ask Your Question
0

Does ros::Subscriber shutdown() block if there is an active callback?

asked 2020-05-01 02:04:29 -0600

billkotsias gravatar image

updated 2020-05-01 04:32:42 -0600

I have tried searching the source code but it seems to be hidden deep inside TopicManager:

If a function callback of a ros::Subscriber is being executed, but the subscriber is shutdown() or goes out of scope, will we get undefined behavior/crash?

I was hoping that shutdown() would block till callback execution finishes.

This also makes me think that the any data living inside the callback should outlive the ros::Subscriber (which would mean that the subscriber should be defined LAST, AFTER any other data (like in a class definition that contains subscriber and data)!

E.g.

struct A {   
  B data; // correct!
  ros::NodeHandle n;
  ros::Subscriber r;
  //B data; // wrong!!! Will die earlier than subscriber, and if class instance
  // dies while callback execution, we'll get a crash
  A() {
      boost::function<void(const MsgConstPtr &msg)> func =
      [this](const MsgConstPtr &msg) {
          this->data.DoStuffWith();
      };
      n.subscribe("topic", 10, func);
  }
};
edit retag flag offensive close merge delete

1 Answer

Sort by ยป oldest newest most voted
0

answered 2020-05-01 04:21:18 -0600

billkotsias gravatar image

updated 2020-05-01 04:54:15 -0600

For the future reader: Yes, all of the above are confirmed.

struct B {
  int b = 1111;
  ~B() {
    b = 0; /* clear memory */
    std::cerr << "B is destroyed!\n";
  }
};
struct A {
  ros::NodeHandle n;
  ros::Publisher pub;
  ros::Subscriber sub;
  B b;
  A() {
    boost::function<void(const std_msgs::StringConstPtr &)> func = [this](const std_msgs::StringConstPtr &msg) {
      std::cerr << "B=" << b.b << " CALLBACK STARTED...waiting 3 seconds\n";
      std::this_thread::sleep_for(std::chrono::seconds(3));
      std::cerr << "B=" << b.b << " CALLBACK FINISHED!!!\n";
    };
    pub = n.advertise<std_msgs::String>("bah", 10, false);
    sub = n.subscribe("bah", 10, func);
  }
};
int main(int argc, char **argv) {
  std::cerr << "STARTED\n";
  ros::init(argc, argv, "a_blah");
  ros::Time::init();

  {
    A *a = new A;
    int start = 100000;
    int count = start;
    ros::AsyncSpinner spinner(0);
    spinner.start();
    while (ros::ok() && --count) {
      if (count == start - 1) {
        std::cerr << "Publishing message\n";
        std_msgs::String msg;
        a->pub.publish(msg);
      }
      if (count == start / 2) {
        std::cerr << "Deleting a...\n";
        delete a;
        a = nullptr;
        std::cerr << "Deleting a FINISHED####\n";
      }
    }
    spinner.stop();
  }

And this prints:

STARTED
Publishing message
B=1111 CALLBACK STARTED...waiting 3 seconds
Deleting a... 
B is destroyed!
                    <<<BLOCKS FOR ~3 SECONDS>>>
B=0 CALLBACK FINISHED!!!
Deleting a FINISHED####
edit flag offensive delete link more

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

2 followers

Stats

Asked: 2020-05-01 02:04:29 -0600

Seen: 173 times

Last updated: May 01 '20