c++ 什么时候我们需要std::shared_future而不是std::future来进行线程间同步?

des4xlb0  于 2023-02-01  发布在  其他
关注(0)|答案(2)|浏览(241)

我试着测试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 器,以便它可以被传递?
我的意思是,有没有任何情况下,非共享的未来不满足需要或场景,你能帮助解释一下吗?

ss2ws0br

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允许两个线程都“查看”结果,因为它是常量。是的,如果结果需要被传递,则必须复制该结果,但无论如何这是不可避免的。

bvuwiixz

bvuwiixz2#

std::shared_future的一个副本不能从不同的线程使用,除了复制。每个线程必须有自己的std::shared_future副本。
https://en.cppreference.com/w/cpp/thread/shared_future
如果每个线程都通过自己的shared_future对象副本访问同一共享状态,那么从多个线程访问该共享状态是安全的。

相关问题