
--- Peter Dimov <pdimov@mmltd.net> wrote: <snip>
Specific undesirable effects (such as reduced performance) can be bad. Synchronization, by itself, is not. It's merely a way (not the only way) to implement the documented thread safety guarantee of ::run.
Regarding other ways of implementing the demuxer without synchronisation... I'm no expert (not even close) on lock-free lists and the like, but it is my belief that the task_demuxer_service can be implemented using some sort of lock-free list or queue plus some atomic integer operations. The locking_dispatcher implementation is also a candidate for this treatment. When it comes to the epoll_reactor, I think it could be implemented without locking by having it adopt a one-way message passing interface. It would use a locking_dispatcher internally to ensure that the critical regions are not called concurrently. Alternatively the epoll_reactor might be amenable to an implementation using lock-free lists directly, i'm not sure.
(One example of a specific undesirable effect that springs to mind is the possibility of deadlock if a callback invokes ::run.)
Just to clarify, the task demuxer's lock is not held when invoking callbacks. I'm not sure what it actually means for a program to make a nested call to demuxer.run(), but it should not deadlock. The reactor lock is held when making I/O calls, but these are non-blocking. It is also on my to-do list to investigate separating the reactor wait from the subsequent I/O calls so that it can scale better across multiple CPUs (i.e. the I/O calls on different sockets can be made concurrently). Cheers, Chris