通过使用 std::promise 和 std::future,就有了task的全部控制权。
std::promise
允许设置一个值,一个消息,或者一个异常。
该结果可以延迟由promise提供。
std::future
可以从promise获取值,请求性获取,值可用的话就可获取到了。
等待promise的消息通知。
等待可以使用一个相对持续时间或绝对时间点来完成=>替代了条件变量。
创建一个共享future (std::shared_future).
两端的通信端口都可以被moved进一个独立的线程中。
所以通信是在线程间进行的。
// promiseFuture.cpp
#include
#include
#include
#include
void product(std::promise<int>&& intPromise, int a, int b) {
intPromise.set_value(a*b);
}
struct Div {
void operator() (std::promise<int>&& intPromise, int a, int b) const {
intPromise.set_value(a / b);
}
};
int main() {
int a = 20;
int b = 10;
std::cout << std::endl;
// 定义 promises
std::promise<int> prodPromise;
std::promise<int> divPromise;
// 获取promise的future
std::future<int> prodResult = prodPromise.get_future();
std::future<int> divResult = divPromise.get_future();
// 独立线程中计算
std::thread prodThread(product, std::move(prodPromise), a, b);
Div div;
std::thread divThread(div, std::move(divPromise), a, b);
// 获取结果
std::cout << "20*10= " << prodResult.get() << std::endl;
std::cout << "20/10= " << divResult.get() << std::endl;
prodThread.join();
divThread.join();
std::cout << std::endl;
}
线程prodThread(第36行)使用了乘法函数(第8~10行),proPromise(第32行)和a、b两数。
想要明白线程prodThread的参数,你必须看一下函数的特点。
prodThread线程第一个参数是个callable,就是上面提到的乘法函数。
这个乘法函数需要一个右值引用的promise()和两个数字。
这就是线程proThread的后三个参数的含义。
在第36行使用std::move创建了一个右值引用。
呐,剩下的就是小菜一碟。
线程divThread(第38行)将数字a和b做了除法运算。
干活的呢,是用了类Div(第12~18行)的实例对象div。
div是个函数对象。
这些future是通过调用prodResult.get() 和 divResult.get() 获取相应的值。
默认情况下,在promise和future之间是一对一关系的。
但是,std::shared_future 支持了一个一对多的关系,即一个promise多个future。
std::shared_future特征:
std::shared_future divResult= divPromise.get_future()
调用所创建。管理std::shared_future是特殊的。
// sharedFuture.cpp
#include
#include
#include
#include
#include
std::mutex coutMutex;
struct Div {
void operator()(std::promise<int>&& intPromise, int a, int b) {
try {
if (b == 0) throw std::runtime_error("illegal division by zero");
intPromise.set_value(a / b);
}
catch (...) {
intPromise.set_exception(std::current_exception());
}
}
};
struct Requestor {
void operator ()(std::shared_future<int> shaFut) {
// 锁住 std::cout,使输出不乱
std::lock_guard<std::mutex> coutGuard(coutMutex);
// 获取线程id
std::cout << "threadId(" << std::this_thread::get_id() << "): ";
// 获取结果
try {
std::cout << "20/10= " << shaFut.get() << std::endl;
}
catch (std::runtime_error& e) {
std::cout << e.what() << std::endl;
}
}
};
int main() {
std::cout << std::endl;
// 定义 promises
std::promise<int> divPromise;
// 获取promise的future
std::shared_future<int> divResult = divPromise.get_future();
// 独立线程中计算
Div div;
std::thread divThread(div, std::move(divPromise), 20, 10);
Requestor req;
std::thread sharedThread1(req, divResult);
std::thread sharedThread2(req, divResult);
std::thread sharedThread3(req, divResult);
std::thread sharedThread4(req, divResult);
std::thread sharedThread5(req, divResult);
divThread.join();
sharedThread1.join();
sharedThread2.join();
sharedThread3.join();
sharedThread4.join();
sharedThread5.join();
std::cout << std::endl;
}
本例中的promise和future都是函数对象。
在做除法的时候,还要小心那个分母。
它必须不能是0,如果是0,将会获得一个异常。
promise通过捕获这个异常处理了这个问题(第18~20行),并把它抛给了future。
future捕获了这个异常并在第40行把它打印了出来。
在第58行,divPromise将被moved并在divThread线程中执行。
于是,std::shared_future在五个线程中拷贝。
我再多说一点:
std::shared_future是可以被拷贝的,不像std::future只能被move。
主线程在第69~73行等待子线程执行结果并打印输出。
原文地址:
http://www.modernescpp.com/index.php/the-special-futures