线程间同步什么时候需要std::shared_future而不是std::future



我试图测试std::shared_future是如何在不同线程之间共享的,因为这些线程都调用其wait()函数,并在调用signal后唤醒。如下:

#include <iostream>
#include <future>
using namespace std;
int main() {
promise<void> p, p1, p2;
auto sf = p.get_future().share(); // This line
auto f1 = [&]() {
p1.set_value();
sf.wait();
return 1;
};
auto f2 = [&]() {
p2.set_value();
sf.wait();
return 2;
};
auto ret1 = async(launch::async, f1);
auto ret2 = async(launch::async, f2);
p1.get_future().wait();
p2.get_future().wait();
p.set_value();
cout << ret1.get() << ", " << ret2.get();
return 0;
}

程序打印1, 2,运行良好。

然后,我使用普通的future对象(而不是shared版本(将auto sf = p.get_future().share();的行更改为auto sf = p.get_future(),编译并运行。我得到了同样的结果:虽然我预计对于非共享版本,只有一个线程会成功wait并返回,而其他线程会挂起。但似乎程序运行正常。

所以我的问题是:我们什么时候需要使用std::shared_future而不是std::future?或者它只是一个像std::shared_ptr这样的对象,作为std::future的一个简单包装器,以便它可以被传递?

我的意思是,是否存在不共享的未来不能满足需求或场景的情况。你能帮忙解释一下吗?

;共享的";CCD_ 14的一部分不是关于等待,而是关于get

我预计对于非共享版本,只有1个线程将成功等待并返回,而其他线程将挂起。

不,这是完全安全的,您可以等待任意多个线程的未来(它是const成员,因此是线程安全的(,并且在设置结果时所有线程都必须取消阻止。但请注意,wait()不能在有人呼叫get()之后呼叫。

不同之处在于你如何得到结果。请记住,std::future代表由std::promise设置的未来结果。

  • std::future::get()按值返回。它只能调用一次,因此只能从一个线程调用
  • std::shared_future::get()返回一个常量引用。它可以从多个线程调用多次。当然,要小心底层对象的线程安全性——它的方法是否真的是线程安全的

此外,std::shared_future可以被克隆,并且多个这样的对象可以引用单个共享状态,即链接到单个承诺对象。只要某个未来/承诺指向共享状态,共享状态就会存在,比如std::shared_ptr<State>

在您的情况下,您稍微滥用了std::shared_future sf,每个等待结果的线程都应该获得自己的克隆。这样,它的寿命是安全的。设想的工作流程是:

  • std::promise被创建,从中获得[第一个]future
  • 承诺是给生产者的,消费者并不知道
  • 未来交给了[每个]消费者[他们可以克隆它,并在必要时传递它]

我的意思是,在任何情况下,非共享的未来都不能满足需求或场景。你能帮忙解释一下吗?

有两个使用者线程,都在等待结果。CCD_ 26将需要恰好一个线程来调用CCD_ 27并以某种方式与另一个线程共享该结果。尽管两者都可以调用CCD_ 28。另一方面,CCD_;视图";结果,因为它是常量。是的,如果需要传递,必须复制结果,但这无论如何都是不可避免的。

除了复制之外,std::shared_future的一个副本不能从不同的线程中使用。每个线程都必须有自己的std::shared_future副本。

https://en.cppreference.com/w/cpp/thread/shared_future

如果每个线程都通过自己的shared_future对象副本访问同一共享状态,那么从多个线程访问同一个共享状态是安全的。

最新更新