I prototyped a bit to investigate this behaviour. Ran the following node:
#!/usr/bin/env python
import rospy
from threading import Lock
from std_msgs.msg import String
mutex = Lock()
def handler(data):
print "Handle called"
mutex.acquire()
print "Handle executed"
import time; time.sleep(10)
mutex.release()
rospy.init_node('test')
rospy.Subscriber('/foo', String, handler)
rospy.spin()
When I publish several individual messages I see that indeed the handler is getting called on another thread while the current handler is still in execution.
rospy pub /foo std_msgs/String "data: 'hello'"
ctrl-c
rospy pub /foo std_msgs/String "data: 'hello'"
ctrl-c
rospy pub /foo std_msgs/String "data: 'hello'"
ctrl-c
I see the output:
Handle called
Handle executed
Handle called
Handle called
... several seconds later
Handle executed
... several seconds later
Handle executed
However, when I publish a msg periodically from the same publish call:
rospy pub /foo std_msgs/String "data: 'hello'"-r 1 # publish once a second
I see this:
Handle called
Handle executed
... 10 seconds pass
Handle called
Handle executed
... 10 seconds pass
Handle called
Handle executed
I know the message is being published once a second, yet it doesn't spawn a new thread for the callback - so something is throttling the msgs until they have been handled.
So the behavior seems to diff depending on if the msgs are arriving from the same process or multiple processes.
I confirmed that it wasn't just a behaviour of rostopic pub by writing a simple node that publishes a msg every second and it behaves the same.
I haven't looked at the ROS code yet so not sure if its the ROS publisher or subscriber code that is throttling in the same process case.
So if you are publishing a topic from a single source then strictly speaking it seems like you don't need a mutex to protect about re-entry by the same topic handler.
However, in my opinion, considering that you (or a future developer) might call the same work function from a different callback or from a timer or from a main loop, or since you can use the same handler for multiple topics (that might come from different processes) and since adding a mutex is pretty easy and low effort and overhead it seems reasonable.
rostopic pubcommands against it. The callback printed several times before any of them could have finished. This means that they were executed in parallel. – Tomas R Feb 01 '20 at 13:23