std::async
exceptions are handledSection: 32.10.9 [futures.async] Status: New Submitter: Jonathan Wakely Opened: 2021-08-23 Last modified: 2021-09-30
Priority: 3
View other active issues in [futures.async].
View all other issues in [futures.async].
View all issues with New status.
Discussion:
32.10.9 [futures.async] (3.1) says:
Any exception propagated from the execution of
invoke(decay-copy(std::forward<F>(f)), decay-copy(std::forward<Args>(args))...)
is stored as the exceptional result in the shared state.
It's not clear whether this includes the evaluation of the decay-copy
calls in the calling
thread, or only the invocation of invoke with the results of those decay-copy
calls.
invoke
, not the
calls to decay-copy
. Exceptions from the decay-copy
calls are propagated
to the caller of std::async
. We should clarify that that's what the standard means.
[2021-09-20; Reflector poll]
Set priority to 3 after reflector poll.
[2021-09-20; Jonathan updates wording to change the Throws: and attempt to align the Effects: with the deferred function case. ]
Previous resolution [SUPERSEDED]:
This wording is relative to N4892.
Modify 32.10.9 [futures.async] as indicated:
template<class F, class... Args> [[nodiscard]] future<invoke_result_t<decay_t<F>, decay_t<Args>...>> async(F&& f, Args&&... args); template<class F, class... Args> [[nodiscard]] future<invoke_result_t<decay_t<F>, decay_t<Args>...>> async(launch policy, F&& f, Args&&... args);-2- Mandates: […]
-3- Effects: The first function behaves the same as a call to the second function with apolicy
argument oflaunch::async | launch::deferred
and the same arguments forF
andArgs
. The second function creates a shared state that is associated with the returnedfuture
object. The further behavior of the second function depends on thepolicy
argument as follows (if more than one of these conditions applies, the implementation may choose any of the corresponding policies):
(3.1) — If
launch::async
is set inpolicy
, callsinvoke(decay-copy(std::forward<F>(f)), decay-copy(std::forward<Args>(args))...)
(22.10.4 [func.require], 32.4.3.3 [thread.thread.constr]) as if in a new thread of execution represented by athread
object with the calls todecay-copy
being evaluated in the thread that calledasync
. Any return value is stored as the result in the shared state. Any exception propagated from theexecution ofcall toinvoke(decay-copy(std::forward<F>(f)), decay-copy(std::forward<Args>(args))...)
invoke
is stored as the exceptional result in the shared state. [Note ?: Exceptions from thedecay-copy
calls are propagated to the caller. — end note] Thethread
object is stored in the shared state and affects the behavior of any asynchronous return objects that reference that state.[…]
Proposed resolution:
This wording is relative to N4892.
Modify 32.10.9 [futures.async] as indicated:
template<class F, class... Args> [[nodiscard]] future<invoke_result_t<decay_t<F>, decay_t<Args>...>> async(F&& f, Args&&... args); template<class F, class... Args> [[nodiscard]] future<invoke_result_t<decay_t<F>, decay_t<Args>...>> async(launch policy, F&& f, Args&&... args);-2- Mandates: […]
-3- Effects: The first function behaves the same as a call to the second function with apolicy
argument oflaunch::async | launch::deferred
and the same arguments forF
andArgs
. The second function creates a shared state that is associated with the returnedfuture
object. The further behavior of the second function depends on thepolicy
argument as follows (if more than one of these conditions applies, the implementation may choose any of the corresponding policies):
(3.1) — If
launch::async
is set inpolicy
, callsinvoke(decay-copy(std::forward<F>(f)), decay-copy(std::forward<Args>(args))...)
(22.10.4 [func.require], 32.4.3.3 [thread.thread.constr]) as if in a new thread of execution represented by athread
object with the calls todecay-copy
being evaluated in the thread that calledasync
. Any return value is stored as the result in the shared state. Any exception propagated from the execution ofinvoke(
is stored as the exceptional result in the shared state, wheredecay-copy(std::forward<F>(f)), decay-copy(std::forward<Args>(args)...)std::move(g), std::move(xyz))g
is the result ofdecay-copy(std::forward<F>(f))
andxyz
is the result ofdecay-copy(std::forward<Args>(args))...
. [Note ?: Exceptions from thedecay-copy
calls are propagated to the caller. — end note] Thethread
object is stored in the shared state and affects the behavior of any asynchronous return objects that reference that state.[…]
[…]
-6- Throws:
system_error
ifpolicy == launch::async
and the implementation is unable to start a new thread;if memory for the internal data structures cannot be allocated; or any exception thrown by the initialization of the objects returned by the
std::bad_allocdecay-copy
calls.