Boost logo

Boost Users :

Subject: Re: [Boost-users] [asio] Using asio for asynchronous event processing
From: Edward Diener (eldiener_at_[hidden])
Date: 2012-05-28 09:42:29


On 5/28/2012 1:32 AM, Anthony Foiani wrote:
> Edward Diener<eldiener_at_[hidden]> writes:
>
>> 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".

More like "the docs don't mesh with my way of understanding".

> 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.

I agree with you that the doc is comprehensive, but I do not think it is
well explained.

>
> (Speaking as one who most certainly did *not* "get it" from the first
> few readings of the docs...)

I am pretty intolerant of library doc, no matter how comprehensive, that
takes the easy path of explaining how to use a library almost
exclusively through the "Tutorial" approach. With the latter, as soon
as anything falls outside the scope of the tutorial(s), the reader is
often lost.

>
>> 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 );

I will look up this io_service::work to see why it is necessary.

>
> 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 );

Unfortunately the software uses Windows threads via VC++ rather than
boost::thread, but I gather that each thread must call
boost::asio::io_service::run().

>
> 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.

Understood.

>
> 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;
>
> // ...
> }
> }

Understood.

>
> 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.

Wish this explanation was in the asio doc. Thanks for clearing this up.

>
> 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.

Yes, somebody else suggested this also, outside of any reference to
asio. An interesting idea I will pursue.

> 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. :)

Thanks very much for the explanation about using asio for generalized
asynchronous operation. As mentioned above, it is not that I think the
doc for asio is not comprehensive but I do think that the author could
have explained much better what asio is about and how it works by
connecting the generalized concepts to the actual classes which
implement them within the library. Failure to do this led me to be
discouraged that I could understand how to use the library. Your brief
explanations helped greatly.


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net