Boost logo

Boost :

From: Braddock Gaskill (braddock_at_[hidden])
Date: 2007-05-02 07:57:04


On Tue, 01 May 2007 15:34:47 -0700, Stjepan Rajko wrote:
>> fi.cancel(); // cancels if not yet complete
>
> Cancellation by cancelling the feature is a cool idea... I assume the
> promise can be notified that all futures have been cancelled via a
> callback? Speaking of... if a function call has many outstanding
> promises/futures (e.g., a return value and a few "out" arguments), is
> there a way to group those all together so that they can be cancelled
> as a group?

When future<T>::cancel() is called, a future_cancel exception is set in the
promise which all future instances are directly or indirectly constructed from.
The futures are all placed in a ready() state, with has_exception() true, and
will throw future_cancel if get() or implicit conversion is invoked.

You can set a simple cancel callback to clean up your side with:
promise<T>::set_cancel_handler(const boost::function<void (void)> &f)

Now, if you have both a return value future, and a set of OutArg futures, you
can handle that in one of two ways:

1) Do nothing.
A nifty feature is that when the last promise object goes out of scope before
being set, all associated futures are immediately set with a "broken_promise"
exception. So when you remove your copy of the promise objects, your waiting callers
get a broken_promise.

2) Maintain a list of promises and cancel them all yourself with whatever
exception or value you want.

>> 5) I want a basic timeout
>> fi.timed_wait(100 /*ms*/);
>> if (!fi.ready()) fi.cancel();
>
> OK, but I think similar functionality should also be added to the rpc
> interface - it might be useful to be able to set a flat timeout for an
> individual function (or all functions), and then cancel the promise in

Yeah, I'm sure you'll want a bit more power and probably a few optional
parameters in your 'rpc()' call. Maybe:

future<T> rpc(RpcParameterSet, F func, ARG1, ..., ARGN)

You may also want to not return a future directly, but perhaps return some
rpc_call_handle type which is implicitly convertable to a future.

rpc_call_handle<T> rpc(...)

The rpc_call_handle may have a more powerful rpc-specific interface. Since it
is implicitly convertable to a future<T>, the user can either choose to ignore
it and accept a simple future<T> with the above usage, or make use of the
handle for whatever rpc-specific interface is needed.

> I do plan to add exception transportation. Is it possible to have the
> future throw a custom (specified by the promise) exception? Your
> point 3) suggests that this is possible also.

Yes, within certain limits.
Thank Peter Dimov for his exception_ptr handling.
In fact, looking at my code now I think I could improve my implementation to
allow throwing arbitrary exception types. This is one of those "early" areas.

>> 7) I have both a return value and an "Out" argument:
>> future<int> multiplied;
>> future<int> fi = rpc(add_and_mult, 1, 2, multiplied);
>> cout << "1+2 = " << fi << "\n";
>> cout << "1*2 = " << multiplied << "\n";
>
> ATM, seems like future doesn't have a default constructor, so
> future<int> multiplied; doesn't compile.

Heh, sorry about that...you are correct. A future must by constructed from a
promise or another future, since a default-constructed future would never get set.

Options:
1) change to
promise<int> multiplied;
and pass the promise to the rpc call.

2) Pass the Out arg future by reference, and replace it with a future
constructed from a promise which the rpc() call creates. Work-around for the
lack of default constructor would be:

future<int> multiplied(promise<int>()); //will immediately be set to broken_promise, but that okay.
(or ask me to provide a default constructor which does this, which is probably a good idea)

I don't like (1) because it blurs the divide between future holder and promise
fulfiller, and breaks the broken_promise mechanism. So I guess I should add
that default constructor, eh? :)

> Also, if the argument was "InOut" rather than just "Out", we'll need

Well, if you use the pass-by-reference future solution above, then you COULD
pass in an already-set future, and then have the rpc() call take that value and
then assign the referenced future to a new promise. I'm not sure I like that
though, it seems abusive and confusing.

> some documentation of the features - I've been getting a lot from the
> code and the test cases, but sometimes the intended use escapes me.

Yes, I need to write some real documentation. :)

Please continue to ask me and I will provide support. I know the
implementation will benefit from it. We can move to private e-mail if you
prefer (braddock_at_[hidden]).

Braddock Gaskill
Dockside Vision Inc


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