Passing the futures from the argument-pack functions through a function-call
boundary forces the runtime to perform all the async() calls _first,_ then
make a separate pass through the futures to obtain results.
Introduce Runner and Example classes to collect and ultimately run lambdas
illustrating use of each different wait_something() variant.
Move Verbose up to the top for use by Runner. Similarly, move sleeper() for
use by those lambdas.
The body of main() then reduces to a Runner::run() call.
Now that wait_first_simple() is again based on Done (a bool protected by a
condition variable) rather than a barrier(2), have to introduce
wait_all_simple_impl() to manage the barrier.
This reverts commit 59a3afd209, reinstating the
Done wrapper.
While it is true that a barrier(2) will wake up when the second fiber calls
wait(), it then _resets._ This means that the _third_ fiber will wait() for
the fourth, and so on. If an odd number of fibers binds that barrier, the last
of them will hang until shutdown.
We want Done.wait() to wake up on the first notify() call, and for every
subsequent notify() call to be a no-op. Apparently Done is the correct
mechanism after all.
We now have:
wait_any_value(): for when passed functions cannot throw exceptions;
wait_first_outcome(): get earliest result/exception;
wait_first_success(): get first non-exception result.