
Hi Carlo, --- Carlo Wood <carlo@alinoe.com> wrote:
Can someone explain to me how it is possible that libACE doesn't use IO completion ports by default?! (Or at all) :)
ACE does support IO completion ports, it just does it through the Proactor pattern. I.e. ACE supports two different patterns for event demultiplexing: Reactor and Proactor.
Next question that comes to mind: is asio creating any threads itself in order to achieve its normal functionality (on windows)?
Yes, it has an internal thread for doing timers and simulating asynchronous connect/accept. However asio will *never* deliver a callback to application code from such a thread. There is a rule that callbacks will only be invoked from a thread that calls demuxer::run().
- The timer resolution of 1 second is too low (see below). Would you be willing to revise/change that part of the interface?
The timers use an asio::time class that includes both a seconds and a microseconds component. I opted to just show the seconds in the tutorial for simplicity.
[ A resolution of 1 second means that you can request 1 second and get 0 seconds (ie, you call now() 1 microsecond before it would return the next integer, add 1 and request the time out with that). A better timer interface, one that I use myself in my networking library, is to always work with "times" as offsets relative to a function returning 'now()'. The value returned by 'now()' should not change in between calls to the system function that actually waits for events (it is only updated once per mainloop loop thus). When requesting a time event you would for example do:
asio::timer t(d, seconds(5));
instead of
asio::timer t(d, asio::time::now() + 5);
The advantage is that if you request 1 second this way, you will get a much more accurate 'second' because internally the clock has microsecond accuracy (ie, select(2) on linux) or at least milisecond accuracy.
First, it has been my experience that, in network applications, working with "absolute" times (i.e. relative to the epoch) is a more useful approach. Further, as I said above, the timers do also use microseconds. So to set a timer for half a second from now: asio::timer t(d, asio::time::now() + asio::time(0, 500000)); or to "bump" a timer along by a further .1 seconds say, you would go: t.expiry(t.expiry() + asio::time(0, 100000));
- What happens when asio::demuxer::run is running (and waiting/sleeping for events) and then the application receives a signal?
Good question :) At the moment I do not do any special handling of signals (and in general I avoid their use), and it's up to the program to do its own signal handling. It's something on my todo list.
- Is it possible to treat signals as events that are dispatched from the mainloop?
If not, then I think direct support for this has to be added. A signal handler can be called at almost any moment in the code and can therefore not use system resources, or shared resources, of any kind. You can't even have it wait for a mutex. Basically all a signal handler can do is set an atomic flag that there has been a signal.
The approach I have been considering is to have an internal thread doing a sigwait, and then have it post the events through the demuxer. Once doing this I would consider that all signals should be treated like other events and that they should not have any special effect on the demuxer (although they might have a default event handler which calls demuxer.interrupt()).
- asio::thread doesn't belong in the library (its a handy thing, but just doesn't belong HERE).
I totally agree. Initially I took a purist approach and did not provide any thread class, instead telling people to use something else, like boost::thread or ACE_Task. However, one of my goals was to allow people to use asio without linking to any non-system libraries (i.e. header-files only) to minimise barriers to using asio, and neither boost::thread nor ACE fit the bill here. And as spawning a thread to run the demuxer was such a common requirement, a minimal asio::thread was created. Regards, Chris