当我们使用 std::thread 创建线程时, 他会忽略线程函数的返回值, 假如我们要获取这个线程的返回值,就要通过全局变量或者传递引用的再加上一些同步机制的方式获取返回值。这样做确实可以实现,但是很麻烦,不如直接使用 c++ 帮我们封装好的模板类
future, promise以及async 这几个模板类就是帮我们做这件事的
std::future
- 头文件
future - 简介
顾名思义,future 就像一个存储着未来结果的容器,它代表了一个异步操作的结果。我们可以检查结果是否已经有了, 或者阻塞等待这个结果
std::promise
- 头文件
简介
直接看代码#include <chrono> #include <thread> #include <iostream> #include <future> using namespace std; void f(std::promise<int>& pro) { this_thread::sleep_for(chrono::seconds(1)); pro.set_value(1); } int main() { int a = 0; std::promise<int> pro; std::future<int> fut = pro.get_future(); thread t1(f, std::ref(pro)); auto res = fut.get(); cout << res << endl; t1.join(); }
主线程在 t1 这个线程执行pro.set_value(1); 之前都会阻塞在 fut.get() 上, promise 就是一个承诺, 承诺未来会有一个值, 我们要做的时通过 promise 调用 get_future 获取 一个 future 对象,来在未来的某一个时刻拿到这个值
通过上面的代码我们也就模拟了这样一个场景, 新建一个线程, 执行一些耗时的操作,然后拿到返回值, 通过使用 std::promise 就实现了这样一个功能, 不需要我们自己去实现一些同步机制去处理了
std::async
async 的作用是是创建一个异步的任务, std::async 函数会返回一个 future 对象, 我们可以通过这个future 对象来获取任务的返回值
示例
#include <chrono>
#include <iostream>
#include <thread>
#include <future>
using namespace std;
int main() {
future<int> fut = async(launch::async, []{ // 这里的启动策略 有两种取值
this_thread::sleep_for(chrono::seconds(1));
return 1;
}); // 后边还可以给任务传参,这里没有写
cout << "-------------" << endl;
this_thread::sleep_for(chrono::seconds(1));
cout << "-------------" << endl;
cout << fut.get() << endl; // 这里会等待 async 的任务返回值
cout << "-------------" << endl;
return 0;
}
两种启动策略
- launch::async 这个会直接异步启动任务
- launch::deferred 这个延期到我们调用 future.get() 时子线程才会被创建以执行任务
若没有指定策略,则会执行默认策略,将会由操作系统决定是否启动新的线程。