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.
The casual reader, on encountering these in the Fiber examples directory,
might otherwise assume they're intended to illustrate something about the
Fiber library.
when_any_simple() is "simple" in the sense that we don't care about return
values or possible exceptions -- we only want to know when the shortest
subtask completes.
This source is a work in progress. We intend to add more cases.
This covers both generic callbacks (adapt_callbacks.cpp,
adapt_method_calls.cpp) and custom Asio completion tokens (yield.hpp,
promise_completion_token.hpp, detail/yield.hpp, detail/promise_handler.hpp).
Mark up the relevant source files to provide code snippets for callbacks.qbk.
This illustrates how to interface a synchronous Fiber function with an async
API whose notification consists of an abstract base class with virtual
success/error methods.
In essence, yield_t et al. become very like use_future_t et al. The only real
difference is the async_result return type and get() method. Factor out common
functionality into promise_completion_token and promise_handler.
Remove the boost::fibers::asio::spawn() function and its basic_yield_context
infrastructure. Fix up all existing references in example source code.
sched_algorithm_with_properties<> must intercept awakened() calls before
forwarding control to the subclass override. That pretty much requires two
different virtual methods: one for sched_algorithm subclasses WITHOUT
properties, the other for sched_algorithm_with_properties subclasses.
Originally we used a different name (awakened_props()), but that was
bothersome. It makes more sense to use a different awakened() overload
instead, one that passes in the relevant properties object.
Fix examples/priority.cpp accordingly.
Also delegate instantiation of a new properties object to new_properties()
virtual method. Overriding this method allows you to customize allocation,
instead of sched_algorithm_with_properties<> unconditionally putting the new
properties object on the heap. Validate the new_properties() return value.