Skip to content

Commit 04e50a9

Browse files
committed
1. 修改第三章线程存储期的措辞
2. 修改第四章,补充 `std::async` 的执行策略在 MSVC STL 的例外特殊情况
1 parent 47db5af commit 04e50a9

File tree

2 files changed

+21
-1
lines changed

2 files changed

+21
-1
lines changed

md/03共享数据.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,7 @@ MSVC 无法使用 GCC 的编译器扩展,GCC 也肯定无法使用 MSVC 的扩
957957
958958
> ### 注意事项
959959
>
960-
> 需要注意的是,在 MSVC 的实现中,`std::async` 策略为 [`launch::async`](https://zh.cppreference.com/w/cpp/thread/launch) 却并不是每次都创建一个新的线程,而是从线程池获取线程。**这意味着无法保证线程局部变量在任务完成时会被销毁**。如果线程被回收并用于新的 `std::async` 调用,则旧的线程局部变量仍然存在。因此,**建议不要将线程局部变量与 `std::async` 一起使用**。[文档](https://learn.microsoft.com/zh-cn/cpp/standard-library/future-functions?view=msvc-170)。
960+
> 需要注意的是,在 MSVC 的实现中,如果 `std::async` 策略为 [`launch::async`](https://zh.cppreference.com/w/cpp/thread/launch) ,但却并不是每次都创建一个新的线程,而是从线程池获取线程。**这意味着无法保证线程局部变量在任务完成时会被销毁**。如果线程被回收并用于新的 `std::async` 调用,则旧的线程局部变量仍然存在。因此,**建议不要将线程局部变量与 `std::async` 一起使用**。[文档](https://learn.microsoft.com/zh-cn/cpp/standard-library/future-functions?view=msvc-170)。
961961
>
962962
> 虽然还没有讲 `std::async` ,不过还是可以注意一下这个问题,我们用一个简单的示例为你展示:
963963
>

md/04同步操作.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,26 @@ int main(){
387387

388388
而我们先前一直没有写明这个参数,是因为 `std::async` 函数模板有两个**重载**,不给出执行策略就是以:`std::launch::async | std::launch::deferred` 调用另一个重载版本(这一点中在[源码](https://github.com/microsoft/STL/blob/f54203f/stl/inc/future#L1425-L1430)中很明显),此策略表示由实现选择到底是否创建线程执行异步任务。典型情况是,如果系统资源充足,并且异步任务的执行不会导致性能问题,那么系统可能会选择在新线程中执行任务。但是,如果系统资源有限,或者延迟执行可以提高性能或节省资源,那么系统可能会选择延迟执行。
389389

390+
> 然而值得注意的是,在 MSVC STL 的实现中,`launch::async | launch::deferred``launch::async` 执行策略毫无区别,[**源码**](https://github.com/microsoft/STL/blob/f54203f/stl/inc/future#L1400-L1410)如下:
391+
>
392+
> ```cpp
393+
> template <class _Ret, class _Fty>
394+
> _Associated_state<typename _P_arg_type<_Ret>::type>* _Get_associated_state(launch _Psync, _Fty&& _Fnarg) {
395+
> // construct associated asynchronous state object for the launch type
396+
> switch (_Psync) { // select launch type
397+
> case launch::deferred:
398+
> return new _Deferred_async_state<_Ret>(_STD forward<_Fty>(_Fnarg));
399+
> case launch::async: // TRANSITION, fixed in vMajorNext, should create a new thread here
400+
> default:
401+
> return new _Task_async_state<_Ret>(_STD forward<_Fty>(_Fnarg));
402+
> }
403+
> }
404+
> ```
405+
>
406+
> 且 `_Task_async_state` 会通过 [`::Concurrency::create_task`](https://github.com/microsoft/STL/blob/f54203f/stl/inc/future#L663-L665) 从线程池中获取线程并执行任务返回包装对象。
407+
>
408+
> 简而言之,使用 `std::async`,只要不是 `launch::deferred` 策略,那么 MSVC STL 实现中都是必然在线程中执行任务。因为是线程池,所以执行新任务是否创建新线程,任务执行完毕线程是否立即销毁,***不确定***。
409+
390410
我们来展示一下:
391411
392412
```cpp

0 commit comments

Comments
 (0)