目录
1.3 std::launch::async | std::launch::deferred
在 C++ 标准库中,std::async 是用于创建并发任务的工具,而第一个参数决定了任务的调度策略。这个参数可以是一个枚举类型,属于 std::launch 枚举类,用于控制如何启动并执行线程任务。常用的值有 std::launch::async 和 std::launch::deferred,你也可以组合这些值来指定不同的执行策略。
1. std::launch 参数选项
1.1. std::launch::async
- 描述:std::launch::async 强制任务在新的线程中异步执行,也就是说它会立即启动一个新的线程来执行提供的任务。
- 执行方式:如果指定了 std::launch::async,任务会在独立的线程中运行,并行执行。
- 特性:这意味着任务在主线程之外被调度,主线程和新任务可以并行工作。
std::future<int> result = std::async(std::launch::async, threadFunction);
在上面的代码中,threadFunction 会在新的线程中执行,主线程继续运行而不会被阻塞,除非调用了 result.get() 来等待结果。
1.2 std::launch::deferred
-
描述:std::launch::deferred 表示任务执行是“延迟的”。也就是说,任务不会立即启动,而是延迟到调用 std::future 的 get() 或 wait() 时才会执行。
-
执行方式:如果指定了 std::launch::deferred,任务不会立即在新线程中执行,而是在调用结果时才会执行,且是在调用者的线程中运行(同步执行)。
-
特性:这种方式可以理解为懒惰执行,只有在需要的时候才去运行任务,且不会在独立的线程中执行。
std::future<int> result = std::async(std::launch::deferred, threadFunction);
在这个代码中,threadFunction 不会立即执行,而是在调用 result.get() 时才会被执行,并且是在主线程中执行。
1.3 std::launch::async | std::launch::deferred
-
描述:当使用组合参数 std::launch::async | std::launch::deferred 时,系统可以选择以异步方式执行任务,也可以选择延迟执行,具体由实现(运行时)决定。
-
执行方式:它可能立即在新的线程中异步执行,也可能延迟到调用 get() 或 wait() 时才执行,这取决于实现的调度策略。通常是由系统根据资源和任务负载来选择合适的策略。
std::future<int> result = std::async(std::launch::async | std::launch::deferred, threadFunction);
这种使用方式更灵活,但不可预测,因为最终是由系统来决定以哪种方式执行。
2. C++ 标准库的 std::async
的实现
2.1 标准库源码
_EXPORT_STD template <class _Fty, class... _ArgTypes>
_NODISCARD_ASYNC future<_Invoke_result_t<decay_t<_Fty>, decay_t<_ArgTypes>...>> async(
launch _Policy, _Fty&& _Fnarg, _ArgTypes&&... _Args) {
// manages a callable object launched with supplied policy
using _Ret = _Invoke_result_t<decay_t<_Fty>, decay_t<_ArgTypes>...>;
using _Ptype = typename _P_arg_type<_Ret>::type;
_Promise<_Ptype> _Pr(
_Get_associated_state<_Ret>(_Policy, _Fake_no_copy_callable_adapter<_Fty, _ArgTypes...>(
_STD forward<_Fty>(_Fnarg), _STD forward<_ArgTypes>(_Args)...)));
return future<_Ret>(_From_raw_state_tag{}, _Pr._Get_state_for_future());
}
_EXPORT_STD template <class _Fty, class... _ArgTypes>
_NODISCARD_ASYNC future<_Invoke_result_t<decay_t<_Fty>, decay_t<_ArgTypes>...>> async(
_Fty&& _Fnarg, _ArgTypes&&... _Args) {
// manages a callable object launched with default policy
return _STD async(launch::async | launch::deferred, _STD forward<_Fty>(_Fnarg), _STD forward<_ArgTypes>(_Args)...);
}
2.2 源码分析
在 C++ 标准库的 std::async
的实现代码中,可以看到两个函数模板,它们分别实现了两种形式的 std::async
:
(1) 第一种形式允许传递一个显式的 launch
策略。
(2) 第二种形式没有显式传递 launch
策略,使用默认策略(launch::async | launch::deferred
)。
这两个 async
函数模板用于管理可调用对象的执行,返回一个包含执行结果的 std::future
对象,以便可以在未来的某个时间点获取任务的结果。
-
模板参数:
-
_Fty
:类型为调用对象,可以是函数、函数对象、lambda
表达式等。 -
_ArgTypes...
:可变参数,用于传递给调用对象的参数。
-
-
返回类型:
-
返回类型为
future<_Invoke_result_t<decay_t<_Fty>, decay_t<_ArgTypes>...>>
,这是一个std::future
对象,用于获取调用对象的返回值。
-
3. 总结
- std::launch::async:任务会在一个新的线程中立即执行,适用于希望任务异步并行处理的场景。
- std::launch::deferred:任务延迟执行,直到明确需要时(调用 get() 或 wait())。适用于需要延迟计算,避免无谓的资源消耗。
- std::launch::async | std::launch::deferred:具体执行策略由系统决定,提供更多的灵活性,但其行为不可预知。
std::launch 参数的选择取决于任务的特性和系统资源的管理。如果任务是时间消耗型并且需要并发执行,推荐使用 std::launch::async;如果任务不急于执行,可以考虑使用 std::launch::deferred 来节省系统资源。