C++11多线程 – Part 8:std::future,std::promise以及线程的返回值

Magicsoftware 2020-06-01

翻译自:https://thispointer.com//c11-multithreading-part-8-stdfuture-stdpromise-and-returning-values-from-thread/

std::future对象可以与async,std::packaged_task和std::promise一起使用。 本文主要关注将std::future与std::promise对象一起使用。

很多时候,我们遇到希望线程返回结果的情况。
现在的问题是如何做到这一点?

让我们举个例子
假设在我们的应用程序中,我们创建了一个压缩给定文件夹的线程,并且我们希望该线程返回新的zip文件名及其大小。
现在,我们有两种方法

1.) 旧方法:使用指针在线程之间共享数据

将指针传递给新线程,该线程将在其中设置数据。 然后直到在主线程中使用条件变量继续等待。 当新线程设置数据并向条件变量发出信号时,主线程将唤醒并从该指针获取数据。
为了简单起见,我们使用了一个条件变量,一个互斥量和一个指针,即3个项来捕获返回的值。
现在假设我们希望该线程在不同的时间点返回3个不同的值,那么问题将变得更加复杂。 是否有一个简单的解决方案可以从线程返回值。
使用std::future的答案是肯定的,为此查看下一个解决方案。

2.) C++11方式:使用std::future和std::promise

std::future是一个类模板,其对象存储将来的值。
现在这个未来的值到底是什么。

实际上,一个std::future对象在内部存储了将分配的值,并且还提供了一种访问该值的机制,即使用get()成员函数。 但是,如果有人尝试在get()函数可用之前访问future的此关联值,则get()函数将阻塞直到该值不可用。

std::promise也是一个类模板,其对象承诺将来会设置该值。 每个std::promise对象都有一个关联的std::future对象,一旦该值由std::promise对象设置,它将给出该值。

一个std::promise对象与其关联的std::future对象共享数据。

让我们一步一步来看看,在Thread1中创建一个std::promise对象。

std::promise<int> promiseObj;

到目前为止,这个promise对象没有任何相关的值。但它给了我们一个承诺,肯定会有人在其中设定该值
一旦设置好它,就可以通过关联的std::future对象获取该值。

但是现在假设线程1创建了这个promise对象并将其传递给线程2对象。现在线程1如何知道线程2何时将在这个promise对象中设置值?

答案是使用std::future对象。

每个std::promise对象都有一个关联的std::future对象,其他人可以通过它获取promise设置的值。
因此,线程1将创建std::promise对象,然后在将std::promise对象传递给线程2之前从中获取std::future对象。

std::future<int> futureObj = promiseObj.get_future();

现在线程1将传递promiseObj给线程2
然后线程1通过std::future的get函数获取线程2在std::promise中设置的值,

int val = futureObj.get();

但如果线程2尚未设置值,则此调用将被阻止,直到线程2在promise对象中设置值,即。

promiseObj.set_value(45);

查看下图中的完整流程:
?C++11多线程 – Part 8:std::future,std::promise以及线程的返回值

让我们看一个完整的std::future和std::promise示例,

#include <iostream>
#include <thread>
#include <future>
 
void initiazer(std::promise<int> * promObj)
{
    std::cout<<"Inside Thread"<<std::endl;     promObj->set_value(35);
}
 
int main()
{
    std::promise<int> promiseObj;
    std::future<int> futureObj = promiseObj.get_future();
    std::thread th(initiazer, &promiseObj);
    std::cout<<futureObj.get()<<std::endl;
    th.join();
    return 0;
}

如果在设置值之前std::promise对象被破坏,则对关联的std::future对象调用get()函数将引发异常。

这是一部分,如果您想要您的线程在不同的时间点返回多个值,那么只需在线程中传递多个std::promise对象,并从关联的多个std::future对象中获取多个返回值。

相关推荐