C++ promise和future

通过使用 std::promise 和 std::future,就有了task的全部控制权。

  • std::promise
    允许设置一个值,一个消息,或者一个异常。
    该结果可以延迟由promise提供。

  • std::future
    可以从promise获取值,请求性获取,值可用的话就可获取到了。
    等待promise的消息通知。
    等待可以使用一个相对持续时间或绝对时间点来完成=>替代了条件变量。
    创建一个共享future (std::shared_future).

两端的通信端口都可以被moved进一个独立的线程中。
所以通信是在线程间进行的。

// promiseFuture.cpp

#include <future>
#include <iostream>
#include <thread>
#include <utility>

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特征:

  • 1、允许你独立于其它future获取promise的值
  • 2、和std::future有一样的接口。
  • 3、可以被一个 std::future 类型的变量 fut 调用fut.share()创建。
  • 4、可以被一个std::promise 变量 divPromise通过 std::shared_future<int> divResult= divPromise.get_future()调用所创建。

管理std::shared_future是特殊的。

// sharedFuture.cpp

#include <exception>
#include <future>
#include <iostream>
#include <thread>
#include <utility>

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

猜你喜欢

转载自blog.csdn.net/y396397735/article/details/82460166
今日推荐