std::async(std::launch::deferred) + std::future::then的行为

21
通过使用std::launch::deferred标志调用std::async才能实现延迟未来(deferred future)的想法是,只有在某人尝试等待或提取未来值或异常时,才会调用回调函数,此时才不会执行回调。
如果我使用std::future::then将一个继续项(continuation)附加到延迟未来上会发生什么?延迟未来会丢失(then会使未来失效),并返回一个新的未来。
在这种情况下,根据标准,应该发生什么?新的未来是否也是延迟未来?它会死锁吗?最新文档中没有解答这个问题。

4
一份较早的规范草案(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3721.pdf)提到:如果父任务的策略为 launch::deferred,而子任务没有指定启动策略或调度器,则会通过立即调用.wait() 来填充父任务,并且前面任务的策略为 launch::deferred。 - Matthias247
5
然而,在新版本中我找不到这个了:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0159r0.html。 - Matthias247
1个回答

2
在我看来,这似乎是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值-这应该在TS/标准中明确说明。如果这不是有意的,则需要更改标准文本。
请注意,这些更改不会出现在2018年发布的N4762草案标准中。
我不确定标准应该如何修复这个问题;.then的语义对于shared_future而言是合理的,但对于future而言则不是,不同的语义将会令人惊讶。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接