Boost logo

Boost :

Subject: [boost] [thread] Alternate future implementation and future islands.
From: Giovanni Piero Deretta (gpderetta_at_[hidden])
Date: 2015-03-17 17:42:56


[cc'ing a few of the participants of the old thread]

Hi All,

Back in January, there was an interesting long thread about the
problem of interoperation between futures of different libraries and
the ability wait for heterogeneous futures. Different solutions were
discussed like standardizing the future shared state or having an
unified kernel wait object.

I just wanted to share my attempt on a solution on the problem. The
code can be found at
https://github.com/gpderetta/libtask/blob/master/future.hpp (other
interesting files are shared_future.hpp event.hpp and
tests/future_test.cpp). It is an implementation a subset of the
current boost and std future interface. In particular it has promise,
future, shared_future, future::then, wait_any, wait_all. Most
important missing piece are timed waits (for lack of, ahem, time, but
should be easy to implement). The implementation requires c++14 and is
only lightly tested, it should be treated as a proof of concept, not
production-ready code.

A few key design points:

* The wait strategy is not part of the future implementation (although
a default is provided). future::get, future::wait, wait_all and
wait_any are parametrized by the wait strategy.

* The design aims to streamline and make as fast as possible future
and promise at the cost of a slower shared_future (although there is
room for improvement).

* The wait strategy only deals with 'event' objects, which act as a
bridge between the future and the promise.

The event object is really my the core of my contribution; it can be
thought of as the essence of future<void>::then; alternatively it can
be seen as a pure user space synchronization primitive.

Other features of this implementation:

* Other than in the blocking strategy itself, the future and promise
implementation have no sources of blocking (no mutexes, not even spin
locks).

* The shared state is not reference counted.

To demonstrate the generality of the waiting concept, I have
implemented a few waiter objects.

  * cv_waiter: this is simply a waiter on top of an std::mutex + cond var.

  * futex_waiter (linux): an atomic counter + a futex, possibly more
efficient than the cv_waiter

  * sem_waiter (posix): a waiter implemented on top of a posix
semaphore. More portable than the futex waiter and possibly more
efficient than the cv_waiter

  * fd_waiter(linux, possibly posix): a waiter implemented on top of
linux eventfd (for portability it can also be implemented on top of a
pipe); you can use select with futures!

  * task_waiter: a completely userspace based coroutine waiter which
switches to another coroutine on wait and resumes the original
coroutine on signal.

  * scheduler_waiter: another coroutine based waiter, but on top of an
userspace task scheduler. On wait switch to the next ready task, on
signal enqueue the waiting task to the back of the ready queue.

I know that there is a plan to reimplement a new version of
boost::threads, hopefully this implementation can contribute a few
ideas.

HTH,

-- gpd


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk