Boost logo

Boost :

From: Frank Mori Hess (frank.hess_at_[hidden])
Date: 2008-05-30 14:47:18

Hash: SHA1

On Friday 30 May 2008 09:25 am, Johan Torp wrote:
> Anthony Williams-4 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 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. 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 haven't fully explored the uses of wait
callbacks though, maybe something can be made to work.

Currently, I have implemented solution (2). It seems to work well enough.
Exceptions thrown in the combiner are transported to the returned future<R>.
However, it does mean that a combiner which blocks or takes a long time can
cause the promise-fulfilling thread to stall running it.

Solution (3) has the advantage that it insulates the promise-fulfilling thread
from the possibility of being stalled by a future-waiting thread which
inserts a slow-running combiner. However, it is a relatively heavyweight
solution, since I'd expect the typical combiner to be a fairly trivial and
quick function to execute.
Version: GnuPG v1.4.6 (GNU/Linux)


Boost list run by bdawes at, gregod at, cpdaniel at, john at