|
Boost : |
From: Howard Hinnant (hinnant_at_[hidden])
Date: 2007-03-14 21:01:19
On Mar 14, 2007, at 8:01 PM, Peter Dimov wrote:
> Howard Hinnant wrote:
>
>>
>>>
>>>> What if there existed a:
>>
>>>
>>>>
>>
>>>
>>>> template <class R>
>>
>>>
>>>> template <class F>
>>
>>>
>>>> promise_functor<R, F>
>>
>>>
>>>> promise<R>::operator()(F f);
>
> I'd actually expect from this syntax to call f and install the
> result into
> the promise in one easy step. :-)
That sounds like a thread launch, which indeed ought to be easy.
We've got (at least) 4 basic concepts floating around here:
* return_value<R>
This is a private implementation detail class that nobody ever sees.
It is not copyable nor movable. It represents the result of a
computation, which can be either normal or exceptional. It has
getters and setters for normal and exceptional results. It lives on
the heap and various handles share its ownership.
* future<R> // return_value getter
This forwards a getter request to return_value<R>. The getter may
need to wait for a signal from a setter.
* promise<R> // return_value setter
This is a setter of return_value<R>, signaling any waiting getters.
Setting normal or exceptional result is explicit.
* functor<R, F> // return_value setter
This is a functor that executes a function F and stores the normal or
exceptional result in a return_value<R>, possibly via a promise<R>.
The result setting is implicit, depending on whether F returns
normally, or has an exception propagate out of it.
Purposefully (and wisely imho) left out of this mix is what actually
executes a setter for return_value<R>. functor<R, F> and promise<R>
are simply thin interfaces to setting return_value<R>. But they don't
represent asynchronous execution. Thus you can create a function that
calls promise<R>::set(r) which is asynchronously executed, say in a
thread or a thread_pool. Or you can adapt an existing function by
constructing a functor<R, F> with it, and then execute that adapted
function in a thread or thread_pool. Either way, the setting of
return_value can happen synchronously, in a dedicated thread
asynchronously, or be queued in a container of functors (possibly
priority sorted) waiting to be processed.
Ultimately I think we want to support syntax along the lines of:
future<T> t = f( b );
c = g( d );
e = h(t(), c);
whereby functors and promises are hidden in relatively low level code,
and high level code can just get a future, assume that it is being
executed asap, and then join with it later. Perhaps that morphs the
above example into:
std::thread_pool launch_in_pool;
int main()
{
std::future<T> t = launch_in_pool(std::bind(f, b));
c = g( d );
e = h(t(), c);
}
-Howard
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk