
Le 05/09/15 02:04, Giovanni Piero Deretta a écrit :
On Fri, Sep 4, 2015 at 11:56 PM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> wrote:
Hi Giovanni,
boost::future has a lot of design issues. I will welcome and base class from which boost::future can inherit as it is quite difficult to maintain it by myself :(. I'm a little bit skeptical about the approach, but who knows. what are your concerns in particular?
Basically what I would like is to decouple the signalling of a future shared_state, as done by e.g. the promise, from the action to be taken. The intuition is that most efficient implementations of synchronization primitives are based on a fast lock free user space signalling path plus a slow kernel path in case there are waiters. My idea is to decouple the slow path from the actual signalling implementation. The decoupling is done via an interface like this:
struct signalable { virtual void signal() = 0; atomic<signalable *> next = 0; };
An actual signalable implementation could invoke a continuation (unifying then and wait), signalling a condition variable, an event, a file descriptor, switching to another fiber etc.
The signaler side has something like this:
struct signaler { void signal();
bool try_wait(signalable *); bool try_unwait(signalable*); };
Note this is not virtual. In fact it could simply be a concept. Try_wait attempts to add the signalable to the wait list for the signaler. Failure means that the signaler was signaled in the meantime. try_unwait attempts to remove the signalable from the wait list. Failure also means that the signaler was signaled in the meantime.
The signaler can be implemented lock_free except in the case in which try_unwait is called *and* there are multiple waiters. I believe this case can be handled with a spinlock just for mutual exclusion between unsignalers (try_waiters and signal can still be lock free), but I have yet to implement it
With this interface a future can be implemented without any additional synchronization.
For example the default implementation of 'then' would simply allocate a new shared state for the returned future which inherit from signalable and register it to the shared_state of the previous continuation. The callback is allocated inline in the shared_state. When signal is called, the callback is invoked.
The default wait of course would create a wait object on the stack (or have a thread local one) which also implements the signalable interface (a portable implementation would be based on a condition variable + boolean flat + mutex). A timed wait need to use the try_unwait interface if the clock times out.
Sorry for the rambling, hopefully the idea is a bit clearer.
I have shared my implementation previously. This is the link again:
https://github.com/gpderetta/libtask/blob/master/future.hpp
Note: incomplete, buggy and definitely not production ready. Giovanni, I'm all for adapting Boost.Thread to any global solution to this problem. What we need first is some one working on it, and showing that we are able to efficiently implement when_all/when_any for some kind of future concept. Then we can try to see how to make boost::future/std::future ...... models of this concept. If you have ideas on how this can work, a POC and time, I propose you to work on it and propose such a library to Boost. I don't believe it is fair to add a link to a ongoing work implementation during the review of a library having a different scope.
Note that boost::future and boost::thread have some interactions (at thead exit family functions) that need to be taken in account
I imagine that can be tricky. Is it much more complex than the thread holding a pointer to the shared state to be made ready on exit?
It is not a question of how complex it can be. It is a matter of public interfaces. We don't have such public interface on the standard and I believe that we need something like that. It is not a good thing that futures and threads be so dependent. The difficulty is defining the interface that makes them (futures/thread) independent without falling to a specific implementation. Thanks for re-rasing these interaction problems, but I believe that these should be handled outside the scope of this review. I suggest you to start a new thread. Vicente