Boost logo

Boost :

Subject: Re: [boost] future/packaged_task Sean Parent design
From: Giovanni Piero Deretta (gpderetta_at_[hidden])
Date: 2015-06-25 08:11:11


On 24 Jun 2015 8:08 am, "Vicente J. Botet Escriba" <vicente.botet_at_[hidden]>
wrote:
>
> Le 24/06/15 02:18, Giovanni Piero Deretta a écrit :
>
>> On Wed, Jun 24, 2015 at 12:09 AM, Vicente J. Botet Escriba
>> <vicente.botet_at_[hidden]> wrote:

>
>> which opens a lot of
>> optimiation opportunities (for example if the future is non copyable
>> non movable, no memory allocation is required).
>
> Sean' future is copyable and movable.
> Do you mean if the stored value? Are thinking of the future<void>
specialization?
> When no memory allocation will be needed?
>

The default future will allocate, but a non-movable non-copiable variant is
conceivable that stores the shared state inline. You get a
promise/packaged_task from it and pass it to the producer which need not to
know.

>>
>>> His future library doesn't include a shared_future as the future
contains a
>>> value that can be observed several times.
>>
>> This is my biggest issue with Sean's design. Sharing the state among
>> multiple consumes pretty much requires heavy weight synchronization.
>
> Could you elaborate?
> It this different for std::shared_future?
>

I can chose not to use shared_future and use a plain future if I'm
concerned about the shared count cost. Note that now I believe that this
aspect of Sean design is implementable without cost if the future is never
copied.

>> But see below.
>>
>>> The continuation takes the value and not the future.
>>> So a future can have
>>> several continuations.
>>
>> What's the thread safety guarantees of future? 'As safe as int' or,
>> for example, concurrent calls to .then are allowed? If the former, a
>> copy could be a real deep copy (a new shared state is allocated and
>> broadcasting is internally done via 'then'). That's not how Sean
>> future is currently implemented though.
>
> Of course, concurrent calls to .then must be allowed. I don't see when
would you need the copy of the shared state.
>

Well you do not need to allow concurrent calls to then if you allow copying
the future. Every thread can use its own copy of the future, although I see
why Sean designed it this way: a future is a placeholder for the underlying
type and pure reads are not racy for sane types.

>>
>>> If the store type is movable only, then the future
>>> can have only one continuation.
>>> Not really strange coming from Sean, future and packaged_task are
copyables
>>> :)
>>> One more thing, there is not get no wait, but a get_try that return an
>>> optional<T>.
>>>
>> Intresting, so if a consumer needs wait must implement it on top of
>> then. This is fine, but you need a way to unregister a 'then'.
>
> I don't know. The std::experimental::future::then is the TS hasn't way to
unregister a continuation. Why do you think it is needed now? It is because
the future is shared?
>

Sean future doesn't have wait for example. If you want to implement timed
waits on top of then you need a way to unregister a waiter. Similarly for
wait_any. You can work around it of course.

[...]
>>>
>>> What are you missing ?
>>
>> [...]
>>
>> The when_any continuation probably needs to be passed the all the
>> futures instead of just the value that is ready, so that it can be
>> called recursively.
>
>
> I would consider when_any as having associated a variant of the Ts as
value type. The continuation should then be an overload of the
alternatives. The continuation passed to all the futures could be an
internal one that is called just once and cancelled just before the first
call.
>
> Could you elaborate the recursive part?
>

Let say I have N futures. As soon as one them is ready I want to do
something. I Call when_any with a continuation. After that I might want
wait again for the remaining N-1 futures and maybe rearm the one that just
got ready. If the continuation had access to all the futures then it would
only need to call when_any again with itself as the continuation.

This is equivalent to calling an hypothetical blocking wait_any in a loop.

>>
>> when_any also requires the ability to unregister a continuation from a
>> future, otherwise if called 'in a loop' the number of continuations
>> associated with futures will grow.
>
> You are right that they will grow. I'm wondering if this is a real
interface issue or a QOI.
>
> Needs this use case a special consideration even if it could decrease the
performances of more usual cases?
>

My use case is implementing a coroutine variant of wait_any efficiently on
top of when_any. See:

https://github.com/gpderetta/libtask/blob/master/tests/future_test.cpp

(Look for wait_any)


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