Boost C++ Libraries of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards


Return Errorcode

The AsyncAPI::init_write() callback passes only an errorcode. If we simply want the blocking wrapper to return that errorcode, this is an extremely straightforward use of promise<> and future<>:

AsyncAPI::errorcode write_ec( AsyncAPI & api, std::string const& data) {
    boost::fibers::promise< AsyncAPI::errorcode > promise;
    boost::fibers::future< AsyncAPI::errorcode > future( promise.get_future() );
    // In general, even though we block waiting for future::get() and therefore
    // won't destroy 'promise' until promise::set_value() has been called, we
    // are advised that with threads it's possible for ~promise() to be
    // entered before promise::set_value() has returned. While that shouldn't
    // happen with fibers::promise, a robust way to deal with the lifespan
    // issue is to bind 'promise' into our lambda. Since promise is move-only,
    // use initialization capture.
        [promise=std::move( promise)]( AsyncAPI::errorcode ec) mutable {
                            promise.set_value( ec);

        std::bind([](boost::fibers::promise< AsyncAPI::errorcode > & promise,
                     AsyncAPI::errorcode ec) {
            promise.set_value( ec);
        std::move( promise),
        std::placeholders::_1) );

    return future.get();

All we have to do is:

  1. Instantiate a promise<> of correct type.
  2. Obtain its future<>.
  3. Arrange for the callback to call promise::set_value().
  4. Block on future::get().
[Note] Note

This tactic for resuming a pending fiber works even if the callback is called on a different thread than the one on which the initiating fiber is running. In fact, the example program’s dummy AsyncAPI implementation illustrates that: it simulates async I/O by launching a new thread that sleeps briefly and then calls the relevant callback.