前言
在c++11之前,不论语言或标准库,对并发处理都没有任何支持。随着c++11到来,语言和标准库都得到强化,支持并发编程。
标准库在不同层面分别提供支持,提供了一个高级接口,允许你启动线程,包括传递实参处理结果和异常。同时也提供了一组低层接口,本文主要讲的是前者高级接口。
对于初学者而言,学习多线程的最佳起点就是c++标准库中的std::async()和class std::future<>提供的高级接口
- async()提供一个接口,让一段代码若是可能的话在后台运行成为一个独立的线程。
- class future<>允许你等待线程结束并获取其结果(一个返回值,或者是一个异常)。
演示代码
#include<iostream>
#include<future>
#include<exception>
using namespace std;
int task1(int sum)
{
for (int i = 0; i < 5; i++)
{
sum ++;
cout << sum << endl;
}
return sum;
}
void test1()
{
future<int>f1(async(task1, 1));
future<int>f2(async(task1, 20));
//task1 完成: 如果分离的线程已经完成了则返回结果
//task1未启动:如果线程未被成功启动,则发生阻塞并执行那段线程需要执行的工作
//task1正在执行中: 等待task1执行完发生阻塞
cout << f1.get() << " " << endl;
cout<<f2.get() << endl;
cout << "f1的状态"<<f1.valid() << endl;
future<int>f3(async(launch::async, task1, 30));
future<int>f4(async(launch::deferred, task1, 40));
f4.wait();
}
int main(int argc, char* argv[]) noexcept
{
try {
test1();
}
catch (const exception& e)
{
cerr << e.what();
}
}
代码分析
async函数有两种形式:
- future async(F func,args…)
- future async(launch policy,F func, args…)
其中的 func指的是callable object(如 function,member function function object lambda)。
args表示参数,是func的参数
注意如果是成员函数,则位于该成员函数的第一个参数必须是指向拥有这个成员函数的对象
launch policy共有三种
- launch::async
- launch::deferred
- launch::async|launch::deferred
launch::async表明以异步的方式调用,如果失败就返回system_error异常
launch::deferred形成一个推迟任务。当我们对返回的future调用wait()或get()这个推迟的任务既被同步调用。如果未曾调用wait()或get()则那个推迟的任务绝不会启动。
注意 如果我们未写发射策略则会选择默认的第三种策略.
class std::Future
正如上面的例子我们看到了class std::Future提供了处理并发运算的未来结果的能力,但是我们只能处理该结果一次,既只能使用一次get()第二次调用就会导致不可预期的行为。
然而有时候,多次处理并发运算的未来结果时合理的,基于这个目的c++标准库提供了class std::shared_future,于是我们可以多次调用get()。
注:本文并未涉及并发可能引发的问题,但我的下一篇博客会分享出我的一些个人理解。参考书籍:c++标准库第二版