Boost logo

Boost :

From: Dylan Nicholson (dylan_nicholson_at_[hidden])
Date: 2002-02-26 20:08:09


Just out of curiousity, have you thought about
asynchronous signals/callbacks, in particular across
threads? That has been my general need, and I
recently finalised a solution that works reasonably
well. It is based on the observer pattern, in that
there is a template ABC 'observer' with an on_notify
function that receives events which are of any type
whatsoever. You can post any type of event from
anywhere, and if there are any currently registered
observers, they will pick it up next time you return
to the event processing loop. Because it is always
asynchronous, it's perfectly safe to have the observer
baseclass self-register, even though 'this' isn't
fully initalised.

To receive events in other threads you simply create
an observer in that thread, then create an
event_processor, which registers itself with a global
list of event_processors. Every time an event is
posted, a copy is transmitted to all currently
registered event_proessors. When you tell an
event_processor to process events it extracts events
from its queue and passes them on to all observers
registered in the same thread.

This system does require both a) a unique identifer
for each thread and b) a locking mechanism, but they
can be supplied separately.

Some sample code:

struct some_random_event { };

struct some_observer : observer<some_random_event>
{
 virtual void on_notify(const some_random_event&
event)
 {
   cout << "got a random event!\n";
 }
};

void background_thread()
{
  for (;;)
  {
    /* ... * /
    post_event(some_random_event());
    /* ... * /
  }
}

int main()
{
  some_observer sob;
  event_processor ep;
  start_thread(background_thread);
  for (;;)
     ep.process_events();
}

Because "sob" is created in the primary thread, it
receives all "some_random_event" objects in that
thread. Note you can derive from as many observers as
like, or have has many event_proessors as you like, as
long as there is at most one active processor per
thread.

There are some pitfalls to this design, mainly to do
with the order that you need to create things in (eg
any events posted before the event_processor has been
created won't be picked up), and the fact that events
have to be a copyable type (but you can use a
thread-safe shared_ptr), but other than this I think
it works pretty well. Note that the implementation
requires no casts whatsoever, it works mostly by heavy
use of static template class members.

I wouldn't mind adding in the ability to make
synchronous calls as well (send_event?) which would
only work within a single thread obviously, and would
require some fudging to safely allow self-registering
from the base class (you would have to explicit
request that your observer is now ready to receive
synchronous events, or it wouldn't start receiving
them until after the event processor had been called).

Anyway, just thought I should bring this up.
Obviously the design is fairly fundamental different
to the proposed signal/slot library, but some of the
concepts might be useful.

Dylan

http://movies.yahoo.com.au - Yahoo! Movies
- Vote for your nominees in our online Oscars pool.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk