| Home | Libraries | People | FAQ | More

## when_any / when_all functionality

#### Overview

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 `wait_something()` functions accepting a container of task functions are left as an exercise for the interested reader. Those should actually be simpler. Most of the complexity would arise from overloading the same name for both purposes.

All the source code for this section is found in wait_stuff.cpp.

#### Example Task Function

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:

1. `sleeper()` prints a start message;
2. sleeps for the specified number of milliseconds;
3. if `thrw` is passed as `true`, throws a string description of the passed `item`;
4. else returns the passed `item`.
5. On the way out, `sleeper()` produces a stop message.

This function will feature in the example calls to the various functions presented below.