std::async(std::launch::deferred) + std::future::then 的行为
behaviour of std::async(std::launch::deferred) + std::future::then
延迟未来背后的想法(只能通过使用 std::launch::deferred
标志调用 std::async
来实现)是只有当有人试图等待或提取未来值或异常时才会调用回调未来。到那时回调还没有执行。
如果我使用 std::future::then
将延续附加到延迟的未来会怎样?延迟的未来会丢失(then
使未来无效)并返回一个新的未来。
这样的话,按照标准,应该怎么办?新的未来也是延迟的未来吗?它会陷入僵局吗?最新文档中没有解决这个问题。
在我看来,这似乎是 the TS 中的一个错误。或者至少是一个记录不足的陷阱。
这是来自 TS 的文本:
2.3 [futures.unique_future]/6-10
template <class F>
see below then(F&& func);
Requires:
INVOKE(DECAY_COPY (std::forward<F>(func)), std::move(*this)) shall be a valid expression.
Effects:
The function creates a shared state that is associated with the returned future object. Additionally,
When the object's shared state is ready, the continuation INVOKE(DECAY_COPY(std::forward<F>(func)), std::move(*this))
is called on an unspecified thread of execution with the call to DECAY_COPY()
being evaluated in the thread that called then.
Any value returned from the continuation is stored as the result in the shared state of the resulting future. Any exception propagated from the execution of the continuation is stored as the exceptional result in the shared state of the resulting future.
Returns:
When result_of_t<decay_t<F>(future<R>)>
is future<R2>
, for some type R2, the function returns future<R2>
. Otherwise, the function returns future<result_of_t<decay_t<F>(future<R>)>>
. [ Note: The rule above is referred to as implicit unwrapping. Without this rule, the return type of then taking a callable returning a future<R>
would have been future<future<R>>
. This rule avoids such nested future objects. The type of f2
below is future<int>
and not future<future<int>>
:
[ Example:
future<int> f1 = g();
future<int> f2 = f1.then([](future<int> f) {
future<int> f3 = h();
return f3;
});
— end example ]
— end note ]
Postconditions:
valid() == false
on the original future. valid() == true
on the future returned from then. [ Note: In case of implicit unwrapping, the validity of the future returned from thenfunc cannot be established until after the completion of the continuation. If it is not valid, the resulting future becomes ready with an exception of type std::future_error
, with an error condition of std::future_errc::broken_promise
. — end note ]
延迟的未来任务没有特殊情况。如果延迟的未来任务在调用 .then
之前没有就绪,则无法使其就绪,因此无法调用 func
的衰减副本。
shared_future
的文字类似;在那里,您仍然可以在调用 .then
之后使 shared_future
准备就绪。
如果这是有意的; .then
在未就绪的延迟唯一未来将导致 future
的 return 值永远无法准备好 - 这应该在 TS/standard 中明确.如果不是这样,则需要更改标准文本。
请注意,这些更改未出现在 2018 年发布的 N4762 draft standard 中。
我不确定标准应该如何解决这个问题; .then
语义对于 shared_future
是合理的,但对于 future
则不合理,不同的语义会令人惊讶。
延迟未来背后的想法(只能通过使用 std::launch::deferred
标志调用 std::async
来实现)是只有当有人试图等待或提取未来值或异常时才会调用回调未来。到那时回调还没有执行。
如果我使用 std::future::then
将延续附加到延迟的未来会怎样?延迟的未来会丢失(then
使未来无效)并返回一个新的未来。
这样的话,按照标准,应该怎么办?新的未来也是延迟的未来吗?它会陷入僵局吗?最新文档中没有解决这个问题。
在我看来,这似乎是 the TS 中的一个错误。或者至少是一个记录不足的陷阱。
这是来自 TS 的文本:
2.3 [futures.unique_future]/6-10
template <class F> see below then(F&& func);
Requires:
INVOKE(DECAY_COPY (std::forward<F>(func)), std::move(*this)) shall be a valid expression.
Effects:
The function creates a shared state that is associated with the returned future object. Additionally,
When the object's shared state is ready, the continuation
INVOKE(DECAY_COPY(std::forward<F>(func)), std::move(*this))
is called on an unspecified thread of execution with the call toDECAY_COPY()
being evaluated in the thread that called then.Any value returned from the continuation is stored as the result in the shared state of the resulting future. Any exception propagated from the execution of the continuation is stored as the exceptional result in the shared state of the resulting future.
Returns:
When
result_of_t<decay_t<F>(future<R>)>
isfuture<R2>
, for some type R2, the function returnsfuture<R2>
. Otherwise, the function returnsfuture<result_of_t<decay_t<F>(future<R>)>>
. [ Note: The rule above is referred to as implicit unwrapping. Without this rule, the return type of then taking a callable returning afuture<R>
would have beenfuture<future<R>>
. This rule avoids such nested future objects. The type off2
below isfuture<int>
and notfuture<future<int>>
:[ Example:
future<int> f1 = g(); future<int> f2 = f1.then([](future<int> f) { future<int> f3 = h(); return f3; });
— end example ]
— end note ]
Postconditions:
valid() == false
on the original future.valid() == true
on the future returned from then. [ Note: In case of implicit unwrapping, the validity of the future returned from thenfunc cannot be established until after the completion of the continuation. If it is not valid, the resulting future becomes ready with an exception of typestd::future_error
, with an error condition ofstd::future_errc::broken_promise
. — end note ]
延迟的未来任务没有特殊情况。如果延迟的未来任务在调用 .then
之前没有就绪,则无法使其就绪,因此无法调用 func
的衰减副本。
shared_future
的文字类似;在那里,您仍然可以在调用 .then
之后使 shared_future
准备就绪。
如果这是有意的; .then
在未就绪的延迟唯一未来将导致 future
的 return 值永远无法准备好 - 这应该在 TS/standard 中明确.如果不是这样,则需要更改标准文本。
请注意,这些更改未出现在 2018 年发布的 N4762 draft standard 中。
我不确定标准应该如何解决这个问题; .then
语义对于 shared_future
是合理的,但对于 future
则不合理,不同的语义会令人惊讶。