Boost logo

Boost :

Subject: Re: [boost] [future.then] Should deferred continuation respect status of original future?
From: Vicente J. Botet Escriba (vicente.botet_at_[hidden])
Date: 2017-05-31 10:05:15


Le 31/05/2017 à 09:38, Tomas Sturm via Boost a écrit :
> Hi,
>
> consider this code that wraps some library returning a future:
>
> // some async library
> boost::future<intermediate> DoLongAsyncTask() {
> return myPromise.get_future();
> }
>
> // intermediate translation layer
> boost::future<result> GetResult() {
> return DoLongAsyncTask().then([] (boost::future<intermediate> f) {
> return TranslateToResult(f.get());
> });
> }
>
> // client event loop
> void RunInClientContext() {
> auto myFuture = GetResult();
> while (stuffToDo()) {
> doStuff();
> if (SafeToCallFutureGetWithoutBlocking(myFuture))
> ProcessResult(myFuture.get());
> }
> }
>
> What should the implementation of 'SafeToCallFutureGetWithoutBlocking'
> be?
> Normally, one would write something like:
>
> myFuture.is_ready()
> or
> myFuture.wait_for(chrono::seconds(0)) != future_status::timeout
>
> But this doesn't work in case the implementation of intermediate
> translation layer calls .then
> with launch::deferred! In Boost 1.63 the future returned from
> .then(launch::deferred, ...)
> is always deferred, so wait_for(...) always returns deferred no matter
> what (and is_ready() always
> returns false). In fact, there is no way to implement
> 'SafeToCallFutureGetWithoutBlocking' if
> the translation is to happen in the context of the client
> (launch::deferred).
>
IRC is_ready and what_for 0 can not work for a deferred future.
> Wouldn't it be more natural to respect the status of the original
> future in this case?
> The documentation is already very clear that the continuation is
> executed only after the original
> future is ready. So in case a client asks whether the continuation
> future is ready, and the original
> future is not ready yet, the call should forward to the original
> future instead.
Humm, the future is ready or not. is_ready just tell you that.
>
> What I propose is this:
>
> promise<int> p;
> future<int> f1 = p.get_future();
> future<int> f2 = f1.then(launch::deferred, [] (auto f) { return
> f.get(); });
> assert(f2.wait_for(0) == future_status::timeout);
If I remember correctly this should fail now.
> p.set_value(42);
> assert(f2.wait_for(0) == future_status::deferred);
Note that f2 contains yet a deferred function the continuation.
This should be the case independently of setting the promise now, isn't it?

So what you are asking is that wait_for(0) returns ::timeout " if the
shared state contains a deferred function" and this function will not
block, isn't it?
I don't know if I have this information, and how i could obtain it yet.
>
> Is there any reason for the continuation future to not behave this way?
I believe I understand your need: you don't want to block on your loop
and you want the continuation to be executed in the loop. Using deferred
futures resulting from a continuation is not the solution
This use case has not been considered and I think it merits some time to
consider it.

Best,
Vicente

P.S.

the doc says

"

- |future_status::deferred| if the shared state contains a deferred
function. (Not implemented yet)"

This is not true anymore. I will fix it.

It says also

Effects:

    If |*this| is associated with a shared state, waits until the result
    is ready, or the time specified by |wait_duration| has elapsed. If
    the result is not ready on entry, and the result has a /wait
    callback/ set, that callback is invoked prior to waiting.

And it should have in addition

"

None if the shared state contains a deferred function"

As it is the case for the C++ standard.


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