c++标准库中对线程操作有完善的封装,其中最常用到的如std::thread, std::async。
EffectiveModernCpp中指出,应尽量使用std::async即基于任务的编程而非基于线程的编程。std::thread在前面的文章有提到过,此处仅对std::async作以记录。
正如前面所说,std::async是基于任务的策略,本人理解为对线程操作的更抽象的封装。对比std::thread,其更灵活且可以异步访问结果。
将闭包传递给std::async后,其会返回一个std::future期物,可对期物使用wait()方法等待线程结束,get()方法得到线程返回值。
std::future有三种状态:
std::future_status::ready //线程执行完
std::future_status::timeout //线程超时
std::future_status::deferred //线程延迟执行(还未开始执行)
对std::future对象可使用wait_for(std::chrono::milliseconds)方法得到线程当前的状态
auto fut = std::async(doAsyncWork); ... //主线程的一些操作 fut.wait(); // 在此设置屏障,阻塞到期物的完成 auto res = fut.get(); //得到结果
值得注意的是,系统可以支持的线程数量是有限的,因此若开发者试图创建大于系统支持的线程数量,会抛出std::system_error
异常。
即使没有超出软件线程的限额,仍然可能会遇到资源超额(oversubscription)的麻烦。这是一种当前准备运行的(即未阻塞的)软件线程大于硬件线程的数量的情况。
而std::async有两种启动策略:
std::launch::async
启动策略意味着f
必须异步执行,即在不同的线程。std::launch::deferred
启动策略意味着f
仅当在std::async
返回的future上调用get
或者wait
时才执行。这表示f
推迟到存在这样的调用时才执行
而std::async默认的启动策略是二者的求或,即std::launch::async | std::launch::deferred,因此默认策略允许异步或者同步执行。这种灵活性允许std::async
和标准库的线程管理组件承担线程创建和销毁的责任,避免资源超额,以及平衡负载。这就是使用std::async
并发编程如此方便的原因。
需注意,若使用默认启动策略,使用者便无法得知线程的状态,即无法预测线程是否是同步或异步,是否在等待还是执行。
本文参考EffectiveModernCpp,多为个人思考,仅供参考。
标签:std,launch,future,线程,async,多线程,wait From: https://www.cnblogs.com/Explosion556/p/17484071.html