并发编程 —— 使用期望值等待一次性事件

C++ 标准库中,有两种期望值,使用两种类型模板实现,声明在 <future> 头文件中 :   
唯一期望值 (unique futures)( std::future<> )
共享期望值 (shared    futures)( std::shared_future<> )。

对于简单的一次性事件,比如,在后台运行计算结果, 但是std::thread 并不提供直接接收返回值的机制。
使用std::async和std::future来实现:

#include <unistd.h>

#include <future>
#include <iostream>

int calculator(int a, int b) { return a + b; }

int main() {
    //使用 std::async 启动一个异步任务,返回一个 std::future 对象
    std::future<int> the_answer = std::async(calculator, 1, 1);
    sleep(2);  // do something
    //调用对象的get(),阻塞返回计算结果
    std::cout << "the answer is " << the_answer.get() << std::endl;
    return 0;
}

std::async允许添加额外的函数参数,具体实例如下:

struct X{
    void foo(int, std::string const&);
    std::string bar(std::string const&);
};

X x;
auto f1 = std::async(&X::foo, &x,42, "Hello");  //调用p->foo(42,"hello"),p是指向x的指针
auto f2 = std::async(&X::bar, x, "goodbye");    //调用tmpx.bar("goodbye"),tmpx是x的拷贝副本

struct Y{
    double operator()(double);
};
Y y;
auto f3 = std::async(Y(), 3.141);          //调用tmpy(3.141),tmpy通过Y的移动构造函数得到
//使用std::ref可以在模板传参的时候传入引用,否则无法传递
auto f4 = std::async(std::ref(y), 2.718);  //调用y(2.718)

X baz(&x);
std::async(baz, std::ref(x));   //调用baz(x)

在默认情况下,期望值是否等待取决于std::async 是否启动一个线程,或是否有任务正在进行同步。
还可以在函数调用之前向 std::async 传递 std::lanuchstd::launch::defered,表明函数调用被延迟到wait()或get()函数调用时才执行,std::launch::async 表明函数必须在其所在的独立线程上执行。如下:

auto f6 = std::async(std::launch::async, Y(), 1, 2);    //在新线程上执行
auto f7 = std::async(std::launch::deferred, std::ref(x));  //在wait()或get()调用时执行

auto f8 = std::async(4. std ::launch ::deferred | std ::launch ::async, baz,
                      std ::ref(x));  //实现选择执行方式
auto f9 = std::async(baz, std ::ref(x));
f7.wait();  //调用延迟函数

在上面的实例中,我们使用std::async让算法分割在各个任务中,从而实现并发。
当然,我们还可以通过其他方法关连 std::future 与任务实例,如,将任务包装入 std::package_task<>实例中
或使用std::promise<>l类型模板显示设置值。

原文地址:https://www.cnblogs.com/y4247464/p/15615330.html