Whilst asynchronous IO (non-blocking descriptors with select/poll/epoll/kqueue etc) is not the most documented thing on the web, there are a handful of good examples.
<
Great design pattern "coroutine" exists to solve this problem.
It's the best of both worlds: tidy code, exactly like synchronous io flow and great performance without context switching, like async io gives. Coroutine looks inside like an odinary synchronous thread, with single instruction pointer. But many coroutines can run within one OS thread (so-called "cooperative multitasking").
Example coroutine code:
void do_some_io() {
blocking_read(something,sizeof(something));
blocking_read(something_else,sizeof(something_else));
blocking_write(something,sizeof(something));
}
Looks like synchronous code, but in fact control flow use another way, like this:
void do_some_io() {
// return control to network io scheduler, to handle another coroutine
blocking_read(something,sizeof(something));
// when "something" is read, scheduler fill given buffer and resume this coroutine
// return control to network io scheduler, to handle another coroutine
CoroSleep( 1000 );
// scheduler create async timer and when it fires, scheduler pass control to this coroutine
...
// and so on
So single threaded scheduler control many coroutines with user-defined code and tidy synchronous-like calls to io.
C++ coroutines implementation example is "boost.coroutine" (actually not a part of boost :) http://www.crystalclearsoftware.com/soc/coroutine/ This library fully implements coroutine mechanics and can use boost.asio as scheduler and async io layer.