为什么我们需要std :: promise和std :: future?

时间:2015-12-09 02:08:39

标签: c++ c++11

我想知道为什么我们需要std :: promise和std :: future?为什么c ++ 11标准将get和set_value分成两个独立的类std :: future和std :: promise? 在post的答案中,它提到了:

  

它被分成这两个独立的"接口"是的   隐藏"写/设置"来自"消费者/读者"。

的功能

我不明白隐藏在这里的好处。但是如果我们只有一个班级"未来&#34 ;?并不简单。例如:promise.set_value可以替换为future.set_value。

2 个答案:

答案 0 :(得分:24)

承诺/未来要解决的问题是将值从一个线程转移到另一个线程。它也可能转移异常。

因此源线程必须有一些可以与之通信的对象,以便将所需的值发送到另一个线程。好吧......谁拥有那个对象?如果源具有指向目标线程所拥有的东西的指针,那么源如何知道目标线程是否已删除该对象?也许目标线程不再关心价值;也许有些事情发生了变化,以至于它决定把你的线程放在地板上而忘掉它。

在某些情况下,这是完全合法的代码。

所以现在问题变成为什么源不拥有承诺并简单地给目的地一个指针/引用呢?嗯,有一个很好的理由:承诺由源线程拥有。一旦源线程终止,promise 将被销毁。从而使目标线程引用了一个被破坏的promise。

糟糕。

因此,唯一可行的解​​决方案是拥有两个完整的对象:一个用于源,一个用于目标。这些对象共享所传输值的所有权。当然,这并不意味着它们不能是相同的类型;你可以拥有类似shared_ptr<promise>或类似的东西。毕竟,promise / future必须在内部有某种共享存储,对吗?

但是,请考虑目前的承诺/未来界面。

promise is non-copyable。您可以移动它,但不能复制它。 future也是不可复制的,但future可以成为可复制的shared_future。因此,您可以拥有多个目的地,但只有一个

promise只能设置值;它甚至无法取回它。 future只能获得价值;它无法设置它。因此,您具有非对称接口,这完全适合此用例。您不希望目标能够设置值,并且源可以检索它。那是向后的代码逻辑。

这就是你想要两个对象的原因。你有一个非对称的界面,最好用两个相关但又分开的类型和对象来处理。

答案 1 :(得分:5)

我会将promise / future视为异步队列(仅用于保存单个值)。

未来是队列的读取结束。承诺是队列的写入结束。

这两者的使用通常是截然不同的:生产者通常只是写入“队列”,而消费只是从中读取。虽然,正如您所指出的那样,生产者可以读取该值,但很少有理由这样做,因此优化该特定操作很少被视为优先考虑。

在通常的方案中,生产者产生价值,并将其置于承诺中。消费者从未来获得价值。每个“客户端”使用一个专门用于一个简单任务的简单接口,因此更容易设计和记录代码,并确保(例如)消费者代码不会混淆与产生价值相关的内容(或反之亦然)。是的,它可以做到这一点,但足够的额外工作,这是不太可能偶然发生的。