我想知道为什么我们需要std :: promise和std :: future?为什么c ++ 11标准将get和set_value分成两个独立的类std :: future和std :: promise?在这篇文章的答案中,它提到:
将它分成这两个独立的"接口"的原因是隐藏"消费者/读者"的"写入/设置"功能.
我不明白隐藏在这里的好处.但如果我们只有一个班级"未来",这不是更简单吗?例如:promise.set_value可以替换为future.set_value.
承诺/未来要解决的问题是将值从一个线程转移到另一个线程.它也可能转移异常.
因此源线程必须有一些可以与之通信的对象,以便将所需的值发送到另一个线程.好吧......谁拥有那个对象?如果源具有指向目标线程所拥有的东西的指针,那么源如何知道目标线程是否已删除该对象?也许目标线程不再关心价值; 也许有些事情发生了变化,以至于它决定把你的线程放在地板上而忘掉它.
在某些情况下,这是完全合法的代码.
所以现在问题变成为什么源不拥有承诺并简单地给目标指向它的指针/引用?嗯,有一个很好的理由:承诺由源线程拥有.一旦源线程终止,承诺将被销毁.从而使目标线程具有对已销毁的承诺的引用.
哎呀.
因此,唯一可行的解决方案是拥有两个完整的对象:一个用于源,一个用于目标.这些对象共享所传输值的所有权.当然,这并不意味着它们不能是同一类型 ; 你可能有类似的东西shared_ptr
或某些东西.毕竟,承诺/未来必须在内部有某种共享存储,对吗?
但是,请考虑它们目前的承诺/未来界面.
promise
是不可复制的.你可以移动它,但不能复制它.future
也是不可复制的,但是future
可以成为shared_future
可复制的.所以你可以有多个目的地,但只有一个来源.
promise
只能设置值; 它甚至无法取回它.future
只能得到价值; 它无法设置它.因此,您具有非对称接口,这完全适合此用例.您不希望目标能够设置值,并且源可以检索它.这是向后的代码逻辑.
这就是你想要两个对象的原因.你有一个非对称的接口,最好用两个相关但独立的类型和对象来处理.
我会将promise/future视为异步队列(仅用于保存单个值).
未来是队列的读取结束.promise是队列的写入结束.
这两者的使用通常是截然不同的:生产者通常只是写入"队列",而消费只是从中读取.虽然,正如您所指出的那样,生产者可以读取该值,但很少有理由这样做,因此优化该特定操作很少被视为优先考虑.
在通常的事物方案中,生产者产生价值,并将其纳入承诺.消费者从未来获得价值.每个"客户端"使用一个专门用于一个简单任务的简单接口,因此更容易设计和记录代码,并确保(例如)消费者代码不会混淆与产生价值相关的内容(或反之亦然).是的,它可以做到这一点,但足够的额外工作,这是不太可能偶然发生的.