[thread_safe_signals] thread safety and more
Hello, I'd like to use thread_safe_signals, and I'm wondering if there're any examples that highlight use-cases where the thread-safety is utilized? For instance, is it safe to connect() from a thread, while the signal is "signaling" in another thread? Is it safe to signal from a thread while another thread might destroy the signal? Another question: what would be the most simple way to do asynchronous signaling? Probably, there already exists something in boost (even not officially released) that provides such a functionality? I mean something like this: at the stage of connecting to a signal I'd like to supply an asynchronous queue along with slot handler, and at the stage of signaling the signal - instead of direct execution of a functor - must just post it to the associated queue (slots' return values are not of interest to me). Thanks, Igor'. _________________________________________________________________ Connect to the next generation of MSN Messenger http://imagine-msn.com/messenger/launch80/default.aspx?locale=en-us&source=wlmailtagline
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Monday 19 May 2008 11:54 am, Igor R. wrote:
Hello,
I'd like to use thread_safe_signals, and I'm wondering if there're any examples that highlight use-cases where the thread-safety is utilized?
Hmm, unfortunately there isn't much like that.
For instance, is it safe to connect() from a thread, while the signal is "signaling" in another thread?
Yes.
Is it safe to signal from a thread while another thread might destroy the signal?
In gernal, there's no way I could prevent someone from trying to use a reference or pointer to a signal object that has already been destroyed. However, if you construct a slot "slotB" with a matching signature directly from a signal "sigA" (not wrapped in a bind) and track sigA, then it is actually safe to run the slot. If sigA has already been destroyed when slotB is run, then slotB will expire and disconnect. If sigA is destroyed while slotB in mid-run, the guts of sigA will be kept alive by slotB until it finished running.
Another question: what would be the most simple way to do asynchronous signaling? Probably, there already exists something in boost (even not officially released) that provides such a functionality? I mean something like this: at the stage of connecting to a signal I'd like to supply an asynchronous queue along with slot handler, and at the stage of signaling the signal - instead of direct execution of a functor - must just post it to the associated queue (slots' return values are not of interest to me).
I don't think such things are within the scope of a signals library. You can however implement your slot to queue whatever you like wherever you like. For example, I've written slots that post events to event queues (QApplication::postEvent from the Qt library) or invoke active objects (poet::active_function from libpoet). Boost Thread, Asio, or Interprocess might be helpful to you in implementing your asynchronous queue. - -- Frank -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) iD8DBQFIMcLO5vihyNWuA4URAv0RAKCJOT+RttKgZyR9C0tKyNisN8OfrwCfRDF/ gTjxNWlr9tSQWNPBN3r/wto= =CNwl -----END PGP SIGNATURE-----
Frank Mori Hess wrote:
Another question: what would be the most simple way to do asynchronous signaling? at the stage of connecting to a signal I'd like to supply an asynchronous queue along with slot handler, and at the stage of signaling the signal - instead of direct execution of a functor - must just post it to the associated queue (slots' return values are not of interest to me).
I don't think such things are within the scope of a signals library. You can however implement your slot to queue whatever you like wherever you like.
It's fairly straightforward, actually, though my experience is admittedly with the older boost::signals library running in a single thread. We took the opposite approach of explicitly queuing event objects. When we "pump" the queue, it sends each of those pending events through the signal to all connected slots.
We took the opposite approach of explicitly queuing event objects. When we "pump" the queue, it sends each of those pending events through the signal to all connected slots.
Could you please elaborate a bit more or just post a short code snippet? You queued functors containing shared_ptr to the original signal objects? You used some generic approach or you made a specific "subscription" function for each type of notification? Thank you.
Igor R wrote:
We took the opposite approach of explicitly queuing event objects. When we "pump" the queue, it sends each of those pending events through the signal to all connected slots.
Could you please elaborate a bit more or just post a short code snippet?
I don't think I'm allowed to post a snippet of the real code. ;-)
You queued functors containing shared_ptr to the original signal objects?
No -- or at least it doesn't sound to me like a match. Here's what we do. Bear in mind that this is a single thread using classic Boost.Signals. Let's say that Event is the data object we intend to propagate through the system. Further suppose this typedef: typedef boost::signal<void(const Event&)> MySignal; We defined an EventQueue object containing an instance of MySignal and (I believe) a std::vector<Event>. We gave EventQueue a method addListener(const MySignal::slot_type&) that just forwards to MySignal::connect(). EventQueue also has a method queueEvent(const Event&) that forwards to std::vector<Event>::push_back(); finally it has a pump() method that I'll describe in a moment. So during initialization, various listeners locate this EventQueue and call its addListener(), typically using boost::bind() to bind a member function of some specific listener-class instance. During normal operation, components call queueEvent(someEvent), which simply adds a copy of someEvent to the EventQueue's std::vector. Once per frame, the controller calls pump(), which iterates through the std::vector<Event>, passing each Event to the MySignal instance. When done, it clears the vector.
You used some generic approach or you made a specific "subscription" function for each type of notification?
Heh -- our app is a hybrid of C++ and Python. We use Boost.Python's convenient dict wrapper to embed a Python dict in our Event object. So you can instantiate an Event (and call queueEvent() with it) in either Python or C++, and any such caller can embed any information it wants in the Event. I realize there's a great controversy raging about free-form events vs. a rigid event hierarchy. Without jumping on a soapbox here, I'll just say that the free-form model works well for us. It does allow us to capture Event objects by copying. If we used polymorphic Events, I guess we could have used a std::vector< boost::shared_ptr<Event> > instead. Anyway, we found the generic approach simple and manageable.
participants (4)
-
Frank Mori Hess
-
Igor R
-
Igor R.
-
Nat Goodspeed