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

时间:2018-07-21 09:31:22

标签: c++ concurrency c++17 stdasync std-future

推迟未来(仅通过使用std::async标志调用std::launch::deferred实现)的想法是,仅当有人尝试等待或拉动未来价值或未来的例外时才调用回调。届时回调将不会执行。

如果我用std::future::then将延期附加到延期的将来会怎样?延期的未来会丢失(then使未来无效),而是返回新的未来。

在这种情况下,根据标准,该怎么办?新的未来也是延期的未来吗?会陷入僵局吗?最新文档未解决此问题。

1 个答案:

答案 0 :(得分:2)

我认为,这似乎是the TS中的错误。或至少没有记录在案的陷阱。

以下是TS中的文字:

2.3 [futures.unique_future] / 6-10

template <class F>
see below then(F&& func);
     

要求:

INVOKE(DECAY_COPY (std::forward<F>(func)), std::move(*this)) shall be a valid expression.
     

效果:

     

该函数创建与返回的将来对象关联的共享状态。另外,

     

当对象的共享状态就绪时,在未指定的执行线程上调用延续INVOKE(DECAY_COPY(std::forward<F>(func)), std::move(*this)),并在随后调用的线程中评估对DECAY_COPY()的调用。

     

从延续返回的任何值都作为结果存储在结果Future的共享状态中。从延续执行中传播的任何异常都会作为例外结果存储在结果期货的共享状态中。

     

返回:

     

result_of_t<decay_t<F>(future<R>)>future<R2>时,对于某些类型R2,该函数返回future<R2>。否则,该函数返回future<result_of_t<decay_t<F>(future<R>)>>。 [注意:上面的规则称为隐式展开。如果没有此规则,则返回可调用的返回future<R>的返回类型将为future<future<R>>。该规则避免了此类嵌套的将来对象。下面的f2的类型是future<int>而不是future<future<int>>

     

[示例:

future<int> f1 = g();
future<int> f2 = f1.then([](future<int> f) {
                    future<int> f3 = h();
                    return f3;
                 });
     

—结束示例]

     

—尾注]

     

后置条件:

     

valid() == false关于原始的未来。 valid() == true关于从那时起返回的未来。 [注意:在隐式展开的情况下,直到连续完成后才能确定从thenfunc返回的future的有效性。如果无效,则产生的Future将准备就绪,但类型为std::future_error的情况除外,错误条件为std::future_errc::broken_promise。 —尾注]

没有特殊情况可推迟将来的任务。如果该延迟的将来任务在调用.then之前尚未准备好,则无法使其准备就绪,因此无法调用func的已衰减副本。

shared_future的文本类似;在那里,您仍然可以在调用shared_future之后使.then准备就绪。

如果有此意图; .then在尚未准备好推迟的唯一未来上将导致future的返回值永远无法准备好-这在TS /标准中应该是明确的。如果不希望这样做,则需要更改标准文本。

请注意,这些更改不会出现在2018年发布的N4762 draft standard中。

我不确定标准应该如何解决; .then的语义对shared_future来说是合理的,但对future来说是不合理的,并且不同的语义会令人惊讶。