executive_smach
executive_smach copied to clipboard
Smach/Python does not respond to Ctrl+C when inside a Concurrency Container
I am using SMACH in that the top-level container is a Concurrency Container. If I want to Ctrl+C the process, it never responds. I believe this is due to the fact that the Concurrency Container is all running in child threads and not in the Main thread.
Are you running the concurrency bare, or are you putting it inside of an IntrospectionServer? If it's the former, you should be able to get your ctrl-c-ability by changing this:
outcome = my_smach_con.execute()
Into this:
# Create a thread to execute the smach container
smach_thread = threading.Thread(target=my_smach_con.execute)
smach_thread.start()
# Wait for ctrl-c
rospy.spin()
# Request the container to preempt
my_smach_con.request_preempt()
# Block until everything is preempted
# (you could do something more complicated to get the execution outcome if you want it)
smach_thread.join()
We do have it attached to an Introspection Server.
We are using a Concurrence behavior at the top most level to also run a Monitor State which monitors for an incoming ROS message which shuts down the entire SMACH state machine.
Edit: The monitor state runs concurrently with the entire state machine, if I wasn't explicit before. Also, I'm using the version released with Fuerte, I'm not sure if that is the latest version or not.
Ok, I'll see if I can repro.
Do you call stop()
on the IntrospectionServer after rospy.spin()
?
I have no calls to rospy.spin() in the code. The concurrence container's execute() function is called and this is where it is blocking (and the ctrl+c is not caught)
I do stop the introspection server, however, after the execute() call returns.
Sorry, what I meant before was an ActionServerWrapper
instead of an IntrospectionServer
. If you call the bare execute()
member function directly, it will block, and there's nothing to tell it to preempt when the interrupt signal comes in. You should try the code that I posted above, when you run the concurrence in a separate thread, and then use the standard ROS signal interrupt handler to stop the call to rospy.spin()
and then you can request that your concurrence preempts itself.
Any progress?
Sorry, I haven't really had a chance to look at this. However, the way we're using SMACH wouldn't allow us to do exactly that, as a process may start up and tear down a state machine many times in its lifetime.
Well even if it's not that code exactly, can you add a rospy shutdown hook which calls request_preempt()
on your top-level container?
Thanks for those hints Jonathan! I also had troubles with ctrl+c and smach.
Unfortunately preempting the state machine after rospy.spin()
returned due to crtl+c (shown in your first comment) doesn't shutdown concurrent state containers properly as they do not wait for their threads to terminate then (because smach.is_shutdown()
is false).
Using the rospy shutdown hook didn't work with a concurrent container.
Therefore I should trigger my preemption monitor state in real world execution for proper shutdown.
Has this been fixed yet? I'm seeing the same thing in Hydro
@athackst What does your top-level script look like? I was never able to reproduce this.
I did you one better and made a package for you so you can test here. I think the problem might be the thread.wait() command. I changed it to poll instead on my branch feature/ConcurrencyFIx and it seems to fix the problem. Can you reproduce it using the package I provided?
@athackst Thanks! That made it really easy to resolve. See the fix here: https://github.com/athackst/smach_concurrency_tests/pull/1
Why should I have to implement a thread pool? Shouldn't the concurrency should do the threading for me? This fix makes that unnecessary : https://github.com/ros/executive_smach/pull/35
Why should I have to implement a thread pool? Shouldn't the concurrency should do the threading for me? This fix makes that unnecessary : #35
We can discuss that over in #35