-
Notifications
You must be signed in to change notification settings - Fork 912
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
roscpp: Multiple AsyncSpinner behavior is confusing and precludes introspection #277
Comments
@davetcoleman, @meyerj, This has direct consequences to writing plugins like gazebo_ros and rtt_rosnode and running them at the same time in the same process. |
A slight modification, instead of |
I've also been recently bitten by this, in a usecase similar to what @jbohren describes. Since the ros wiki entry and the dev documentation don't mention the limitations of the current implementation, it took some digging up (@po1) to figure out what we were doing wrong.
Yes!, this would also allow to start/stop AsyncSpinners from different threads, correct?. |
A bit of background on what Adolfo is asking here: we were thinking of having multiple AsyncSpinners because we want to service multiple, independent CallbackQueues. It makes sense to isolate some functionalities into a separate CallbackQueue, and sometime we only want to service this CallbackQueue when a given set of conditions are met. We tried to |
I agree that this problem should be solved in roscpp's #include <ros/ros.h>
#include <ros/callback_queue.h>
#include <boost/thread.hpp>
struct Foo {
public:
Foo() {
// advertise, subscribe or whatever using the my_queue_ CallbackQueue
queue_thread_ = boost::thread(boost::bind(&Foo::QueueThread, this));
}
~Foo() {
rosnode_.shutdown();
queue_thread_.join();
}
void QueueThread()
{
static const double timeout = 0.01;
while (this->rosnode_.ok())
{
this->my_queue_.callAvailable(ros::WallDuration(timeout));
}
}
private:
ros::NodeHandle rosnode_;
ros::CallbackQueue my_queue_;
boost::thread queue_thread_;
} Of course this example can simply be extended to service the global queue or by adding |
I don't know if this will be of interest to any of you, but I put together two extensions to the NodeHandle class. Both of them are meant to be 100% compatible with regular NodeHandles.
I would love receiving any feedback on this proposal. |
@dirk-thomas What do you think of @po1's rough proposal? |
@meyerj Do you think we should use the custom-callback-approach in |
If the additional spinners and node handles solve a specific need for your use cases please feel free to use them. But I would hesitate to add them to roscpp without further reasons. I would rather like to see proposals how to modify the existing spinners to fit these mentioned needs instead of writing/adding another one. |
I agree with Dirk, it will be better to fix the problem at its source (in a conservative way) rather than extending the API. I don't have all the items and subtleties of this case in mind anymore, but the main problem seemed to be that many independent components sharing the same binary might want their own async spinner. The problem is that so far, This results in all independent components of a whole (e.g. gazebo plugins) to create their own thread and implement a spinner in it. That is to say, re-implement an Basically, if we could replace the existing As for limiting the amount of threads and serializing more work in a single thread, I don't see any easy fix that would not imply adding a new class somewhere, but I haven't looked very hard. |
Yeah that makes sense. One thing that would be useful (and not change the current behavior), at least, is just a boolean-valued function which tells you if an |
@jbohren A pull request for that would be very welcome. Thanks. |
@dirk-thomas I'll put together the PR with the introspection function. Meanwhile, I was looking at this again, and it's not clear to me why you shouldn't be able to call |
Just got bit with the issue of instantiating several asyncspinners to service separate callbackqueues, in the context of a gazebo plugin. @dirk-thomas, any comment on @jbohren's "Meanwhile.."? |
@paulbovbel Afaik the async spinner is designed in a way that prevents two instances to work in parallel since they both use the same global state. As the comment in the PR #377 clarifies if multiple are run they don't do what you would expect them to - all but one are basically not handling any callbacks. @jbohren With #377 being implemented quite some time ago can this ticket be closed? Or can you please clarify what this ticket is about (beside the implemented introspection functionality)? |
Hi All, sorry if my question is not directly related to this topic. Program received signal SIGSEGV, Segmentation fault. |
@ehsan-asadi If you questions is not directly related to this topic then please ask it on answers.ros.org. |
Since there was no feedback in my previous questions in January I assume this ticket has been resolved by #377. If not please comment here with more information. |
Just got bit with the issue of instantiating several AsyncSpinners to service separate CallbackQueues too. |
@rhaschke All spinners share the same mutex:
|
@dirk-thomas Yes, that's the problem. The question was why spinmutex is there. This issue is not resolved, because it is still (for no reason afaics) not possible to have multiple |
@v4hn This ticket is about "Multiple AsyncSpinner behavior is confusing and precludes introspection" and as a result #377 has been implemented to allow checking if another sync spinner is already running. Please create a separate ticket if you want to be able to run multiple async spinners in parallel. Please consider to also provide a pull request for that new feature since I will very likely not have time to work on feature development. Thank you. |
@dirk-thomas Could you give a hint, why the mutexes were introduced at all? As pointed out above, they were introduced in 769af28, referring to "very old bug # 1811". However, # 1811 obviously refers to some old bug tracking system. Could you please point me to that? |
The old issue tracker from Willow Garage times is no more. I don't think that information is available anywhere. |
It's been a long time and I wasn't directly involved with the issue. But I believe that the issue with multiple spinners on the same callback queue was that they did not interleave cleanly and you would get unexpected ordering of the callbacks. Possibly even out of order. The mutex to prevent it was because supporting the interaction between spinners was going to need a notably refactor to work as expected. |
If the issue was only about accessing the callback queue in order, the solution of using a global mutex would be completely wrong. Rather, a mutex local to the callback queue would be required - which is present too (maybe it was introduced later). |
Currently, if you try to create two AsyncSpinner instances this error is emitted:
This is normally not a problem, but if two different systems with ROS plugins are trying to create spinners, there's no way to determine whether spinners currently exist nor is there a way to determine the number of spinning threads.
First, it seems like this should be a warning instead of an error. But more importantly, it seems like the AsyncSpinner class can't determine if it wants to be a handle to a global service or not. You can create any number of AsyncSpinner instances, but they all want to use a single static mutex so only the first one is actually going to function properly.
I'd expect that if I create an AsyncSpinner with
n
threads in one place, and create another AsyncSpinner withm
threads in another place, that there should subsequently ben+m
threads processing ROS callbacks. This shouldn't be hard to implement without changing the API. Would such a change be welcome?The text was updated successfully, but these errors were encountered: