Edward Diener
I do not understand the documentation for asio, or even if it pertains to the programming problem I am trying to solve. The doc, for whatever reason, is poor regarding practical use.
For whatever it's worth, I tend to try to view this as "the docs don't mesh with my way of thinking". The reference is comprehensive, but ASIO is so flexible that even the examples and tutorials can only cover a small portion of the design space; if you don't "get it" from that, then it hurts. (Speaking as one who most certainly did *not* "get it" from the first few readings of the docs...)
I need to design generalized asynchronous events triggered by an event source and handled by an event handler. The event source would trigger an event declared as a callable object, as in boost::function, and an event handler would eventually handle the event asynchronously. The event source and the event handler would be in different threads of an application but not in different applications.
The event source triggers the event but does not block in any way waiting for the event to be processed. The event source may subsequently trigger other asynchronous events to be eventually handled in the same way without blocking.
The event handler is able to check for events periodically from within its own thread.
Each event itself could be a totally different callable object, but the event source and the event handler both know the callable prototype for any given event. The event source and the event handler are completely disconnected in that neither knows about the other. For any given asynchronous event there may be any number of event handlers when an event is triggered.
Can I use asio to implement such a solution ?
I believe so. Further, I believe that you can even strap it onto a signals2 solution (as per your previous question, although maybe you were just exploring options for doing a pure async solution). Here's what should work. In your main program, create an io_service to manage all the events, and add some fake work to it: // in main program boost::asio::io_service io; boost::scoped_ptr< boost::asio::io_service::work > work_ptr( io ); If you want threads that are dedicated to handling events, you can do that by having the thread just run io_service.run: boost::thread handler1( boost::asio::io_service::run, &io ); boost::thread handler2( boost::asio::io_service::run, &io ); Otherwise, you'll have to call io.poll_one() (or some similar variant) to execute work as it becomes available during the allocated slots on your handler threads. In your event generator thread, you might do something like this: // event generator while ( event = wait_for_event() ) { switch ( event.type ) { case MOUSE_EVENT : io.post( boost::bind( handle_mouse_event, event ) ); break; case WINDOW_EVENT : io.post( boost::bind( handle_window_event, event ) ); break; // ... } } You can view the io_service object ("io") as a "work queue", with items peeled off the front and handed out to whatever thread calls "run", "run_one", "poll", or "poll_one" on that same io object. If you find signals2 to be a helpful organizational tool, you can integrate it with ASIO by having signals2 make asynchronous calls to the various slots hooked up to the triggered signal. It's probably a bit hacky, but I wedged that async call into the combiner object used by the signal. First, we define some types at namespace or file scope (I ran into issues using block-scoped types): struct async_combiner_t { typedef void result_type; async_combiner_t( boost::asio::io_service * io_ptr ) : io_ptr( io_ptr ) {} async_combiner_t( const async_combiner_t & ) = default; boost::asio::io_service * io_ptr; template < typename InputIter > void operator()( InputIter first, InputIter last ) { for ( InputIter i = first; i != last; ++i ) io_ptr->post( [=](){ *i; } ); } }; typedef boost::signals2::signal< void (), async_combiner_t > async_sig_t; Now we create the block-scoped objects using those types, and start sending events at them: boost::asio::io_service io; typedef boost::scoped_ptr< boost::asio::io_service::work > work_ptr_t; work_ptr_t work_ptr( new boost::asio::io_service::work( io ) ); const int n_threads = argc > 1 ? boost::lexical_cast< int >( argv[1] ) : 5; boost::thread_group threads; for ( int i = 0; i < n_threads; ++i ) threads.create_thread( [&](){ io.run(); } ); async_combiner_t async_combiner( &io ); async_sig_t async_sig( async_combiner ); async_sig.connect( slot1 ); async_sig.connect( slot2 ); async_sig(); work_ptr.reset(); if ( n_threads ) threads.join_all(); else run_io( io ); Having said that, I am having issues getting that to work with multiple threads; I'm going to post a question here in a bit. The full program is available at: https://github.com/tkil/boost-async/blob/master/async-signals2.cpp Hopefully it'll give you ideas. Hopefully they'll be good ideas. :) Happy hacking, t.