Skip to content

Commit bd41c96

Browse files
committed
增加 std::thread 源码解析的内容
1 parent 8db42b3 commit bd41c96

File tree

2 files changed

+38
-1
lines changed

2 files changed

+38
-1
lines changed

Diff for: md/02使用线程.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -757,7 +757,7 @@ int main(){
757757
758758
了解其实现,才能更好的使用它,同时也能解释其使用与学习中的各种问题。如:
759759
760-
- 为什么默认按值复制
760+
- 如何做到的默认按值复制
761761
- 为什么需要 `std::ref` ?
762762
- 如何支持只能移动的对象?
763763
- 如何做到接受任意[可调用](https://zh.cppreference.com/w/cpp/named_req/Callable)对象?

Diff for: md/详细分析/01thread的构造与源码解析.md

+37
Original file line numberDiff line numberDiff line change
@@ -202,3 +202,40 @@ void _Start(_Fn&& _Fx, _Args&&... _Ax) {
202202
我们这里的源码解析涉及到的 C++ 技术很多,我们也没办法每一个都单独讲,那会显得文章很冗长,而且也不是重点。
203203
204204
相信你也感受到了,**不会模板,你阅读标准库源码,是无稽之谈**,市面上很多教程教学,教导一些实现容器,过度简化了,真要去出错了去看标准库的代码,那是不现实的。不需要模板的水平有多高,也不需要会什么元编程,但是基本的需求得能做到,得会,这里推荐一下:[**现代C++模板教程**](https://github.com/Mq-b/Modern-Cpp-templates-tutorial)。
205+
206+
---
207+
208+
学习完了也不要忘记了回答最初的问题:
209+
210+
1. **如何做到的默认按值复制?**
211+
212+
`_Start` 的第一行代码展示了这一点。我们将传入的所有参数包装成一个元组类型,这些类型先经过 `decay_t` 处理,去除了引用与 cv 限定,自然就实现了默认复制。
213+
214+
```cpp
215+
using _Tuple = tuple<decay_t<_Fn>, decay_t<_Args>...>;
216+
```
217+
218+
2. **为什么需要 `std::ref`**
219+
220+
实现中将类型先经过 `decay` 处理,如果要传递引用,则必须用类包装一下才行,使用 `std::ref` 函数就会返回一个包装对象。
221+
222+
3. **如何支持只能移动的对象?**
223+
224+
参数通过完美转发,最终调用时使用 `std::move`,这在线程实际执行的函数 `_Invoke` 中体现出来:
225+
226+
```cpp
227+
_STD invoke(_STD move(_STD get<_Indices>(_Tup))...);
228+
```
229+
230+
4. 如何做到接受任意[可调用](https://zh.cppreference.com/w/cpp/named_req/Callable)对象?
231+
232+
源码的实现很简单,主要是通过两层包装,最终将 `void*` 指针转换到原类型,然后使用 `std::invoke` 进行调用。
233+
234+
5. **如何创建的线程?**
235+
236+
MSVC STL 调用 Win32 API `_beginthreadex` 创建线程;libstdc++ 调用 `__gthread_create` 函数创建线程,在 Windows 上实际上就是调用 `CreateThread`。
237+
`_beginthreadex` 和 `CreateThread` 都是微软提供的用于创建线程的 C 风格接口,它们的主要区别在于前者依赖于 C 运行时库,而后者更适合纯 Windows API 的情况。使用 `_beginthreadex` 可以确保正确初始化和清理 C 运行时库资源,而 `CreateThread` 则适用于不依赖于 C 运行时库的环境。
238+
239+
6. **传递参数一节中的:“*`std::thread` 内部会将保有的参数副本转换为右值表达式进行传递*”到底是如何做到的?**
240+
241+
这就是第三个问题,差不多,无非是最后调用 `std::invoke` 函数之前,先 `std::move` 了。

0 commit comments

Comments
 (0)