Boost logo

Boost :

From: Johan Torp (johan.torp_at_[hidden])
Date: 2008-05-30 18:10:28


Frank Mori Hess wrote:
>
>> > Alternatively, you could have future_or spawn a thread to run the task
>> > rather than do it lazily as a wait callback.
>>
>> I don't think spawning a thread is acceptable.
>>
>> 1. Starting a new thread is expensive. Thread-pools might help here but
>> they don't exist yet.
>> 2. Context switching is expensive. Typically, the evaluation work is real
>> small. This approach requires an additional context switch compared to if
>> the future-listener performed the evaluation. It might also reduce the
>> performance of a thread-pool if composite futures are frequently
>> evaluated.
>> 3. Composed futures might need to access data belonging to the
>> future-listener in it's evaluation. If the evaluation is performed by a
>> single future-listener, it can use const references. Now such the data
>> needs to be copied or protected by mutexes.
>> 4. Nested composed futures might get a context switch at every depth
>> level.
>>
>> I wouldn't be surprised if the context switching would rule out futures
>> from libraries such as asio or poet. That would be a real shame. Frank or
>> somebody with asio insight, what do you think?
>
> I've been working on the "wait for any/all" issue with libpoet's futures,
> and
> for me it has boiled down to the question of how this function should
> behave:
>
> template<typename R, typename Combiner, typename T1, typename T2, ...,
> typename TN>
> future<R> future_combining_barrier(Combiner combiner, future<T1> f1,
> future<T2> f2, ..., future<TN> fN);
>
> The idea of future_combining_barrier is the returned future<R> gets its
> value
> by calling
>
> combiner(f1.get(), f2.get(), ..., fN.get())
>
> once all the input futures are ready. I see 3 options:
>
> 1) The combiner is run in a future-waiting thread.
> 2) The combiner is run in a promise-fulfilling thread.
> 3) The combiner is run in its own thread.
>

I think this is a very important and difficult design decision. As I
explained above (with the points numbered 1-4), I don't think option 3 is
viable. An additional argument against option 3 is that you can't use
futures in single threaded programs.

My arguments against option 2 is:
A. If the combiner dead-locks, this would spread to the promise-fulfiller.
This would make a bug harder to pin-point.
B. Argument 3 from the 1-4 arguments above
C. You can have exceptions (such as windows se_exceptions, divide by zero,
null pointer use etc ) which you want don't want to catch and set in the
future, but rather would like to catch at the "stack top" of each thread
started (at least the threads you explicitly start yourself). If you catch
and set these exceptions and later re-throw them, you lose the stack trace
inside the combiner.
D. A log typically logs which thread does what. If the promise-fulfiller
executes lots of different foreign threads' code it can become more
difficult to follow program execution.
E. All of the above arguments above are due to executing code which is set
by another foreign thread. I believe there are lots of other effects that
can happen which I haven't thought of. OTOH, the future-listener which
creates the composite future has full control. If the future is shared
between more threads after creation, it can be accompanied by documentation
(i.e. this future will acquire this lock). We do not want this sort of
coupling between the promise-listener and promise-fulfillers.

Frank Mori Hess wrote:
>
> I initially tried to implement option (1) but could not make it work
> satisfactorily with my implementation (which relies on completion
> callbacks).
> Basically, I couldn't get the returned future<R> to work well enough. I
> wanted it to run the combiner without holding any internal library locks,
> and
> also to run its own completion callback without undue goading from
> external
> code.
>

I really hope option 1 is implementable without holding any locks. Could
explain in more detail what problems you ran into?

Frank Mori Hess wrote:
>
> Also, it is easy to accidentally run the combiner in a
> promise-fulfilling thread if the combiner gets run by the future::ready()
> query as well as when waiting.
>

I'm not following you, could you elaborate?

Johan

-- 
View this message in context: http://www.nabble.com/-future--Early-draft-of-wait-for-multiple-futures-interface-tp17242880p17568852.html
Sent from the Boost - Dev mailing list archive at Nabble.com.

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