...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
A bit of wisdom from the early days of computing still holds true today: prefer to model program state using the instruction pointer rather than with Boolean flags. In other words, if the program must “do something” and then do something almost the same, but with minor changes... perhaps parts of that something should be broken out as smaller separate functions, rather than introducing flags to alter the internal behavior of a monolithic function.
To that we would add: prefer to describe control flow using C++ native constructs
such as function calls, if
, while
, for
,
do
et al. rather than as chains
of callbacks.
One of the great strengths of Boost.Fiber is the flexibility it confers on the coder to restructure an application from chains of callbacks to straightforward C++ statement sequence, even when code in that fiber is in fact interleaved with code running in other fibers.
There has been much recent discussion about the benefits of when_any and when_all functionality. When dealing with asynchronous and possibly unreliable services, these are valuable idioms. But of course when_any and when_all are closely tied to the use of chains of callbacks.
This section presents recipes for achieving the same ends, in the context of
a fiber that wants to “do something” when one or more other independent
activities have completed. Accordingly, these are wait_something()
functions rather than when_something()
functions. The expectation is that the calling
fiber asks to launch those independent activities, then waits for them, then
sequentially proceeds with whatever processing depends on those results.
The function names shown (e.g. wait_first_simple()
)
are for illustrative purposes only, because all these functions have been bundled
into a single source file. Presumably, if (say) wait_first_success()
best suits your application needs, you could introduce that variant with the
name wait_any()
.
Note | |
---|---|
The functions presented in this section accept variadic argument lists of
task functions. Corresponding |
All the source code for this section is found in wait_stuff.cpp.
We found it convenient to model an asynchronous task using this function:
template< typename T > T sleeper_impl( T item, int ms, bool thrw = false) { std::ostringstream descb, funcb; descb << item; std::string desc( descb.str() ); funcb << " sleeper(" << item << ")"; Verbose v( funcb.str() ); boost::this_fiber::sleep_for( std::chrono::milliseconds( ms) ); if ( thrw) { throw std::runtime_error( desc); } return item; }
with type-specific sleeper()
“front ends” for std::string
,
double
and int
.
Verbose
simply prints a message
to std::cout
on construction and destruction.
Basically:
sleeper()
prints a start message;
thrw
is passed as true
, throws a string description of the
passed item
;
item
.
sleeper()
produces a stop message.
This function will feature in the example calls to the various functions presented below.