On 1 Sep 2015 2:15 pm, "Agustín K-ballo Bergé"
On 9/1/2015 9:35 AM, Giovanni Piero Deretta wrote:
On 30 Aug 2015 10:04 pm, "Agustín K-ballo Bergé"
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