Boost logo

Boost :

Subject: Re: [boost] [afio] Formal review of Boost.AFIO
From: Giovanni Piero Deretta (gpderetta_at_[hidden])
Date: 2015-09-01 10:43:14


On 1 Sep 2015 2:15 pm, "Agustín K-ballo Bergé" <kaballo86_at_[hidden]>
wrote:
>
> On 9/1/2015 9:35 AM, Giovanni Piero Deretta wrote:
>>
>> On 30 Aug 2015 10:04 pm, "Agustín K-ballo Bergé" <kaballo86_at_[hidden]>
>> wrote:
>>>
>>>
>>> On 8/30/2015 5:06 PM, Niall Douglas wrote:
>>>>
>>>>
>> [...]
>>>>
>>>> 7. future.wait() very rarely blocks in your use scenario i.e. most if
>>>> not nearly all the time the future is ready. If you are blocking, the
>>>> cost of any thread sleep will always dwarf the cost of any future.
>>>
>>>
>>>
>>> `future::wait` should not be a concern, you just spawn a
>>
>> `condition_variable` and attach a fake continuation to the future that
will
>> wake it up. The cv will be stored in the thread stack, which is
guaranteed
>> to stay around since we will be sleeping. This allows the fake
continuation
>> to simply be `reference_wrapper`, for which you only need `sizeof(void*)`
>> embedded storage. Since the (unique) future cannot be used concurrently
>> with `wait`, there can only ever be at most one fake continuation.
>>
>> This is unfortunately not true. Std::future::wait is const, so, without
an
>> explicit prohibition, multiple threads can call it as long as no other
non
>> const function is concurrently called. This is possibly a defect of the
>> standard.
>
>
> Indeed, that is correct. I overlooked that detail, and would have to
check my code if I weren't using a single implementation of waits for both
`future` and `shared_future`.
>

Well I'm not :). Then again, I'm not concerned with adherence to the
standard in my implementation.

>
>>> The situation gets trickier for `wait_for/until`, where you need to
remove
>>> the fake continuation on a timeout without racing.
>>>
>>
>> Also needed to implement wait any.
>
>
> Once `wait` returns the shared-state is ready. You don't even need to
remove the fake continuation pointer, it will never be looked up again.

You do if you want to implement a wait_any interface that blocks until the
first of a number of futures is ready. In that case you must be able to
reissue another wait at a later time. Think 'select'.

>
>
> > A dismissible, efficiently implementable
>>
>> 'then' protocol could be the key for future composition across
libraries. I
>> would prefer if in this case the continuation were pointer sized to allow
>> lock free implementations.
>
>
> I don't think pointer sized continuations would buy you anything, you can
attach multiple continuations to a single shared-state (via
`shared_future`) so you will always end up needing memory allocation
eventually. That doesn't stop you from attaching the pointer to the
continuation decayed-copy in a lock free way.
>

Only if you use shared state. I'm looking at optimising unique futures. My
shared future implementation currently is internally N unique futures plus
a multiplexer.

Also for waits you can always allocate the waiter/signaler on the stack.
The tricky part is handling the race between a dismissal and a signal.

To implement the generic 'then' I do always heap allocate, but I put the
callback inline with the returned future shared state. I use the pointer
sized dismissible 'then' to chain the two shared states.

-- gpd


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