Section: 32.10 [futures] Status: C++11 Submitter: Alberto Ganesh Barbati Opened: 2010-09-14 Last modified: 2016-01-28
Priority: Not Prioritized
View all other issues in [futures].
View all issues with C++11 status.
Discussion:
The current WP N3126 contains ambiguous statements about the
behaviour of functions wait_for
/wait_until
in
case the future refers to a deferred function. Moreover, I believe
it describes a disputable intent, different from the one contained
in the original async proposals, that may have been introduced
inadvertently during the "async cleanup" that occurred recently.
Consider the following case:
int f(); future<int> x = async(launch::deferred, f); future_status s = x.wait_for(chrono::milliseconds(100));
This example raises two questions:
f
invoked?s
?According to the current WP, the answer to question 1 is yes,
because 30.6.9/3 says "The first call to a function waiting for the
associated asynchronous state created by this async call to become
ready shall invoke the deferred function in the thread that called
the waiting function". The answer to question 2, however, is not as
clear. According to 30.6.6/23, s should be
future_status::deferred
because x
refers to a
deferred function that is not running, but it should also be
future_status::ready
because after executing f
(and we saw that f
is always executed) the state becomes
ready. By the way, the expression "deferred function that is not
running" is very unfortunate in itself, because it may apply to
both the case where the function hasn't yet started, as well as the
case where it was executed and completed.
While we clearly have a defect in the WP answering to question
2, it is my opinion that the answer to question 1 is wrong, which
is even worse. Consider that the execution of the function
f
can take an arbitrarily long time. Having
wait_for()
invoke f
is a potential violation of
the reasonable expectation that the execution of
x.wait_for(chrono::milliseconds(100))
shall take at most
100 milliseconds plus a delay dependent on the quality of implementation
and the quality of management (as described in paper N3128).
In fact, previous versions of the WP
clearly specified that only function wait()
is required to
execute the deferred function, while wait_for()
and
wait_until()
shouldn't.
The proposed resolution captures the intent that
wait_for()
and wait_until()
should never attempt
to invoke the deferred function. In other words, the P/R provides
the following answers to the two questions above:
future_status::deferred
In order to simplify the wording, the definition of deferred function has been tweaked so that the function is no longer considered deferred once its evaluation has started, as suggested by Howard.
Discussions in the reflector questioned whether
wait_for()
and wait_until()
should return
immediately or actually wait hoping for a second thread to execute
the deferred function. I believe that waiting could be useful only
in a very specific scenario but detrimental in the general case and
would introduce another source of ambiguity: should
wait_for()
return future_status::deferred
or
future_status::timeout
after the wait? Therefore the P/R
specifies that wait_for
/wait_until
shall return
immediately, which is simpler, easier to explain and more useful in
the general case.
[ Post-Rapperswil ]
Moved to Tentatively Ready after 5 positive votes on c++std-lib.
[ Adopted at 2010-11 Batavia ]
Proposed resolution:
The proposed wording changes are relative to the Final Committee Draft, N3126.
Note to the editor: the proposed wording is meant not be in conflict with any change proposed by paper N3128 "C++ Timeout Specification". Ellipsis are deliberately used to avoid any unintended overlapping.
In [futures.unique_future] 30.6.6/22:
Effects: none if the associated asynchronous state contains a deferred function (30.6.9), otherwise blocks until the associated asynchronous state is ready or [...].
In [futures.unique_future] 30.6.6/23 first bullet:
— future_status::deferred if the associated asynchronous
state contains a deferred function that is not
running.
In [futures.unique_future] 30.6.6/25:
Effects: none if the associated asynchronous state contains a deferred function (30.6.9), otherwise blocks until the associated asynchronous state is ready or [...].
In [futures.unique_future] 30.6.6/26 first bullet:
— future_status::deferred if the associated asynchronous
state contains a deferred function that is not
running.
In [futures.shared_future] 30.6.7/27
Effects: none if the associated asynchronous state contains a deferred function (30.6.9), otherwise blocks until the associated asynchronous state is ready or [...].
In [futures.unique_future] 30.6.7/28 first bullet:
— future_status::deferred if the associated asynchronous
state contains a deferred function that is not
running.
In [futures.shared_future] 30.6.6/30:
Effects: none if the associated asynchronous state contains a deferred function (30.6.9), otherwise blocks until the associated asynchronous state is ready or [...].
In [futures.unique_future] 30.6.7/31 first bullet:
— future_status::deferred if the associated asynchronous
state contains a deferred function that is not
running.
In [futures.atomic_future] 30.6.8/23
Effects: none if the associated asynchronous state contains a deferred function (30.6.9), otherwise blocks until the associated asynchronous state is ready or [...].
In [futures.unique_future] 30.6.8/24 first bullet:
— future_status::deferred if the associated asynchronous
state contains a deferred function that is not
running.
In [futures.atomic_future] 30.6.8/27:
Effects: none if the associated asynchronous state contains a deferred function (30.6.9), otherwise blocks until the associated asynchronous state is ready or [...].
In [futures.unique_future] 30.6.8/28 first bullet:
— future_status::deferred if the associated asynchronous
state contains a deferred function that is not
running.
In [futures.async] 30.6.9/3 second bullet:
[...] The first call to a function
waitingrequiring a non-timed wait for the
associated asynchronous state created by this async call to become
ready shall invoke the deferred function in the thread that called
the waiting function; once evaluation of INVOKE(g,
xyz)
begins, the function is no longer considered
deferred all other calls waiting for the same associated
asynchronous state to become ready shall block until the deferred
function has completed.