C++11标准库增加了获取线程返回值的方法,头文件为<future>,主要包括future
、promise
、packaged_task
、async
四个类。
那么,了解一下各个类的构成以及功能。
1 future
future是一个模板类,它是传输线程返回值(也称为共享状态)的媒介,也可以理解为线程返回的结果就安置在future中。
future | 版本:C++11 头文件<future > |
构造函数 |
默认构函数,是一个无效
|
析构函数 | ~future(); |
get | std::future<T> T get(); 获取共享状态,如果共享状态尚未就绪(比如线程未结束),则堵塞,等效于wait函数。 |
valid | bool valid() const noexcept; 判断future是否有效。无效future有三种情况:一是使用默认构造函数创建的;调用过移动构造函数;三是调用过get函数。 |
wait | void wait() const; 获取共享状态,如果共享状态尚未就绪(比如线程未结束),则堵塞;阻塞结束之后,还需要继续调用get才能获取共享状态,此时get不再阻塞。 |
wait_for | 设置最大阻塞时间 |
wait_until | 设置最大阻塞时刻 |
跟多线程相关的类,大多都有一个特点,就是禁用拷贝构造函数,仅能使用移动构造函数。
单独使用future依然没有办法获取线程的返回值,必须与promise、packaged_task或者async搭配使用。而且,单独创建出来的future对象甚至都没有意义,必须从promise、packaged_task或者async中创建,才有意义。
2 promise
promise对象可以看做是future类的封装,它可以原子的修改future的共享状态。
promise | C++ 11 头文件: <future > |
构造函数 |
默认构造函数,构造一个共享状态为空的
移动构造函数,用原属
|
get_future |
获取共享状态,返回一个 |
set_value | 原子地存储 value 到共享状态,并令状态就绪(future::get结束阻塞 )。 |
set_value_at_thread_exit | 原子地存储 value 到共享状态,而不立即令状态就绪。在当前线程退出时,再令状态就绪。 |
#include <thread>
#include <future>
#include <iostream>
void fun1(std::promise<int> pro) {
std::this_thread::sleep_for(std::chrono::seconds(3));
pro.set_value(100);
return;
};
int main()
{
std::promise<int> pro;
std::future<int> fut = pro.get_future();
std::thread th(&fun1, std::move(pro));
th.detach();
std::cout << fut.get() << std::endl;
}
需要注意的一点是,future的模板类型与线程函数的返回类型无关。上边fun1函数的返回值为void,但是future类型为int。
3 packaged_task
packaged_task是一个类,它主要包含了一个future对象和一个任务,这个任务可以是
函数、 lambda
表达式、 bind
表达式或其他函数对象。
packaged_task | C++11 头文件: <future > |
构造函数 |
|
get_future |
获取共享状态,返回一个 |
()运算符 |
以 |
#include <iostream>
#include <cmath>
#include <thread>
#include <future>
#include <functional>
// 避免对 std::pow 重载集消歧义的独有函数
int f(int x, int y) { return std::pow(x,y); }
void task_lambda()
{
std::packaged_task<int(int,int)> task([](int a, int b) {
return std::pow(a, b);
});
std::future<int> result = task.get_future();
task(2, 9);
std::cout << "task_lambda:\t" << result.get() << '\n';
}
void task_bind()
{
std::packaged_task<int()> task(std::bind(f, 2, 11));
std::future<int> result = task.get_future();
task();
std::cout << "task_bind:\t" << result.get() << '\n';
}
void task_thread()
{
std::packaged_task<int(int,int)> task(f);
std::future<int> result = task.get_future();
std::thread task_td(std::move(task), 2, 10);
task_td.join();
std::cout << "task_thread:\t" << result.get() << '\n';
}
int main()
{
task_lambda();
task_bind();
task_thread();
}
输出:
与promise不同的是,packaged_task任务的返回类型就是future的类型。
4 async
async是一个模板函数,它综合了前边promise和packaged_task的功能,一个函数就可以实现线程创建、任务执行、获取返回值等功能。
async的返回值是一个future对象,async所执行的任务完成后,会令共享状态
进入就绪状态。
#include <thread>
#include <future>
#include <iostream>
#include <unistd.h>
int main()
{
auto ff = std::async(std::launch::async, []{ sleep(2); return 2.3; });
std::cout << ff.get() << std::endl;
}