Question on the callback and other context switching within a ROS node

769 views
Skip to first unread message

Mark Johnston

unread,
Mar 13, 2015, 2:14:00 AM3/13/15
to hbrob...@googlegroups.com

I am sure this is documented somewhere but this  is an important question that would be very nice to put to rest as far as locking requirements on data structures in a given node.
If ROS deals with this issue in a certain way (I doubt it but wanted to ask)  then I can have less clumsy code by avoiding all the pitfalls one can hit with locking.

In a multi-node ROS system with lots of topics consider one of the  ros nodes that has a few callbacks that listen to topics but only one node in this process.

If I populate a queue of data structures from a callback, is the pulling of data from these same data structures safe without a lock?
To say another way:  Is a process global data structure (C++ queue or just structure) used in main() for the ROS node safe to use data that can be modified in those callbacks?

If a callback for subscription to a topic can happen on ANY linux context switch or any ROS call such as ROS_INFO  or  ros::sleep() then my answer is a 'yes a lock is required'.  

In the 'real world' the answer would be of course you have to lock it but ROS is it's own environment and both main() and callbacks are a ROS context on top of linux.
this issue may be a FEATURE of ROS and I want to know if it is or most likely is not a feature.

Since ROS is a single process I wonder if callbacks to listen to topics are asynchronous and can be done from a (thread) context switch out of the ROS  main() loop  OR if those callbacks are ONLY managed when you call something like  ros::spinOnce().

I have been assuming my locks are requred, just asking.
Thanks,
Mark Johnston




Michael Ferguson

unread,
Mar 13, 2015, 2:30:14 AM3/13/15
to hbrob...@googlegroups.com
The answer is: it depends a bit on how your application is built.

In the simplest case, you setup your callbacks and then you call ros::spin() (this covers probably 90% of C++ ROS nodes). spin() then processes the callback queues, and does so in a single thread, and no locks are required. If you use an AsyncSpinner instead of ros::spin(), then you might end up with multiple threads processing the queue, in which case a lock is needed. This page has some details on the various queue processing techniques: http://wiki.ros.org/roscpp/Overview/Callbacks%20and%20Spinning

As a note, if you use actionlib's SimpleActionServer, and specify "true" as the second parameter, an extra thread is created for that server -- but it will only process things that are in the action server's queue.

ROS_INFO and friends are glorified macros and do not deal with the callback queues. Same goes for sleep (note how that linked page shows calling "spinOnce" and then "sleep").

In Python, this is entirely different as each subscribed topic gets a thread (unless this has changed, it is not per subscriber, but rather per subscribed topic). Python also has different threading models for the publishers depending on whether queue_size is set or not (used to be synchronous, if queue_size is set, becomes async) (see https://github.com/ros/ros_comm/issues/169 for the full details).

-Fergs

--
You received this message because you are subscribed to the Google Groups "HomeBrew Robotics Club" group.
To unsubscribe from this group and stop receiving emails from it, send an email to hbrobotics+...@googlegroups.com.
To post to this group, send email to hbrob...@googlegroups.com.
Visit this group at http://groups.google.com/group/hbrobotics.
For more options, visit https://groups.google.com/d/optout.

Austin Hendrix

unread,
Mar 13, 2015, 2:39:12 AM3/13/15
to hbrob...@googlegroups.com, Mark Johnston

By default, ROS only processes callbacks within ros::spinOnce(). With that, you don't need locks.

If you switch to a multithreaded spinner so that your node can process multiple callbacks in parallel, then you'll have multiple threads and you need locks.

-Austin

Mark Johnston

unread,
Mar 13, 2015, 2:44:24 AM3/13/15
to hbrob...@googlegroups.com

Thanks for quick reply Fergs,
 
I am shocked and yet at the same time very pleased with the info in the reply.  I figured it was almost a stupid thing to ask, GLAD I did ask.  In other code written in past and so on any call to any os layer is suspect for a context switch to some other thread including prints and any utility that can do an OS block.   This is great news.    

Yes I use ros::spinOnce() only in this case and figured for SURE it would go out and do stuff or ROS would not work ... LOL
I am shocked that ros::sleep() is 'safe' and that is why I specifically called it out in my question but am very pleased to hear it is not going to allow a topic subscription callback.

This greatly lowers the pain of supporting and writing many ROS apps and is IMHO a fantastic 'feature' of ROS.

Any other home-brew or helper thread spinners in use would of  course force the party to be  BYOL  (bring your own lock  lol) 

Thanks also for the link to more info on this sort of subtle till it crashes your code sort of OS stuff.

Mark
Reply all
Reply to author
Forward
0 new messages