我试着测试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
,工作正常。
然后我用oridinay future
对象,而不是shared
版本,把auto sf = p.get_future().share();
这一行改成了auto sf = p.get_future()
,编译并运行,得到了同样的结果:虽然我预计对于非共享版本,只有一个线程将成功wait
和返回,而其他线程将挂起。但似乎仍然程序运行正常。
所以我的问题是:什么时候我们需要使用std::shared_future
而不是std::future
?或者它只是一个类似std::shared_ptr
的对象,作为std::future
的一个简单 Package 器,以便它可以被传递?
我的意思是,有没有任何情况下,非共享的未来不满足需要或场景,你能帮助解释一下吗?
2条答案
按热度按时间ss2ws0br1#
shared_future
的“共享”部分不是关于“等待”,而是“获得”。我预计对于非共享版本,只有1个线程将成功等待并返回,而其他线程将挂起。
不,这是完全安全的,你可以等待任意多个线程的未来(它是一个常量成员,因此是线程安全的),并且所有线程都必须在结果被设置时解除阻塞。但是要注意的是,
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
。我的意思是,有没有任何情况下,非共享的未来不满足需要或场景,你能帮助解释一下吗?
有两个消费者线程,都在等待结果。
std::future
要求一个线程调用get
,并以某种方式与另一个线程共享结果。虽然两个线程都可以调用wait()
。另一方面,std::shared_future
允许两个线程都“查看”结果,因为它是常量。是的,如果结果需要被传递,则必须复制该结果,但无论如何这是不可避免的。bvuwiixz2#
std::shared_future的一个副本不能从不同的线程使用,除了复制。每个线程必须有自己的std::shared_future副本。
https://en.cppreference.com/w/cpp/thread/shared_future
如果每个线程都通过自己的shared_future对象副本访问同一共享状态,那么从多个线程访问该共享状态是安全的。