C++11中提供的并发元素包括:tasks, futures, threads, mutexes, condition variables, atomic objects(std::atomic 简介) and more。
线程std::thread
thread类实现了操作系统里的线程表示,负责启动和管理线程对象;成功创建一个线程后,即可被调度执行(没有strart等方法来启动);可被 joinable 的 thread 对象必须在他们销毁之前被主线程 join 或者将其设置为 detached(否则会有异常)。
void f1(int n);
void f2(int& n);
int main()
{
int n = 0;
std::thread t1; // t1 is not a thread
std::thread t2(f1, n + 1); // pass by value
std::thread t3(f2, std::ref(n)); // pass by reference
std::thread t4(std::move(t3)); // t4 is now running f2(). t3 is no longer a thread
t2.join();
t4.join(); // 一定要join或设定joinable
}
thread中主要函数:
joinable:检查线程是否可join,即对象是否标识活跃的执行线程;
get_id:返回线程的 id;
native_handle:返回底层实现定义的线程句柄;
hardware_concurrency[静态]:返回实现支持的并发线程数;
join:等待线程执行(阻塞当前线程);
detach:分离线程;
swap:交换两个 thread 对象;
命名空间std::this_thread:
yield:放弃执行,建议再次调度线程(当前线程可能会被再次调度执行,也可能是其他线程执行);
get_id:返回当前线程的线程 id;
sleep_for:使线程休眠一段时间;
sleep_until:暂停当前线程的执行直到特定的时间点;
任务std::async
async(在头文件中)异步地运行函数 f ,并返回最终将保有该函数调用结果的 std::future。 有两种标准的加载策略:
launch::async:fun必须在一个不同(非当前)线程中异步运行;
launch::deferred:fun只有在调用了future(async的返回值)的get或者wait时(wait_for与wait_until无此功效,函数继续deferred)才会执行(同步执行,get与wait的调用者被阻塞直到fun执行完);若没有调用get或wait,则fun永远不会执行。
默认时(不传递策略)为launch::async | launch::deferred:
无法预测fun是否并发运行;
无法预测fun是否运行过(若未调用get与wait,调用时可能已运行,也可能还为运行,然后开始同步运行);
若从 std::async 获得的 std::future 未被移动或绑定到引用,则在完整表达式结尾, std::future 的析构函数将阻塞直至异步计算完成(采用async策略,且为最后一个引用时,会阻塞等待ready后以析构future):
std::async(std::launch::async, []{ f(); }); // 临时量的析构函数等待 f()
std::async(std::launch::async, []{ g(); }); //f() 完成前不开始
// 如下,若默认策略恰好选择了deffered(在负载重时很可能;此问题很难被测试出来),则wait_for循环永远不会退出(状态一直为deferred)
void fAs() {
this_thread::sleep_for(1s);
}
//auto fut = std::async(fAs);
auto fut = std::async(launch::deferred, fAs);
while (fut.wait_for(100ms) != future_status::ready) {
cout // 死循环
}
cout
std::thread与std::async
线程与任务异同:
std::thread没有直接获取返回值的方法,且如果线程中抛出异常,程序会直接崩溃(terminate);
基于线程(thread)的编程需要考虑线程耗尽、超额认购(oversubscription)、加载平衡、新平台适应等问题;而基于任务(async)的编程,默认都已帮助你处理了这些问题;
领取专属 10元无门槛券
私享最新 技术干货