Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion md/02使用线程.md
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ void test(){
}
```

主线程延时 3 秒,这个传入了一个临时对象 `seconds` ,它是模板 [`std::chrono::duration`](https://zh.cppreference.com/w/cpp/chrono/duration) 的别名,以及还有很多其他的时间类型,都基于这个类。说实话挺麻烦的,如果您支持 C++14,建议使用[时间字面量](https://zh.cppreference.com/w/cpp/symbol_index/chrono_literals),在 [`std::chrono_literals`](https://github.com/microsoft/STL/blob/main/stl/inc/__msvc_chrono.hpp#L742-L804) 命名空间中。我们可以改成下面这样:
主线程延时 3 秒,这个传入了一个临时对象 `seconds` ,它是模板 [`std::chrono::duration`](https://zh.cppreference.com/w/cpp/chrono/duration) 的别名,以及还有很多其他的时间类型,都基于这个类。说实话挺麻烦的,如果您支持 C++14,建议使用[时间字面量](https://zh.cppreference.com/w/cpp/symbol_index/chrono_literals),在 [`std::chrono_literals`](https://github.com/microsoft/STL/blob/8e2d724cc1072b4052b14d8c5f81a830b8f1d8cb/stl/inc/__msvc_chrono.hpp#L718-L780) 命名空间中。我们可以改成下面这样:

```cpp
using namespace std::chrono_literals;
Expand Down
2 changes: 1 addition & 1 deletion md/03共享数据.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ void f() {
}
```

那么问题来了,`std::lock_guard` 是如何做到的呢?它是怎么实现的呢?首先顾名思义,这是一个“管理类”模板,用来管理互斥量的上锁与解锁,我们来看它的 [MSVC 实现](https://github.com/microsoft/STL/blob/main/stl/inc/mutex#L452-L473):
那么问题来了,`std::lock_guard` 是如何做到的呢?它是怎么实现的呢?首先顾名思义,这是一个“管理类”模板,用来管理互斥量的上锁与解锁,我们来看它的 [MSVC 实现](https://github.com/microsoft/STL/blob/8e2d724cc1072b4052b14d8c5f81a830b8f1d8cb/stl/inc/mutex#L452-L473):

```cpp
_EXPORT_STD template <class _Mutex>
Expand Down
12 changes: 6 additions & 6 deletions md/详细分析/01thread的构造与源码解析.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@

我们这单章是为了专门解释一下 `std::thread` 是如何构造的,是如何创建线程传递参数的,让你彻底了解这个类。

我们以 **MSVC** 实现的 [`std::thread`](https://github.com/microsoft/STL/blob/main/stl/inc/thread) 代码进行讲解,新版 MSVC STL 的实现完全基于 **C++14**,所以即使是 C++11 引入的标准库设施,实现中可能也是使用到了 C++14 的东西。
我们以 **MSVC** 实现的 [`std::thread`](https://github.com/microsoft/STL/blob/8e2d724cc1072b4052b14d8c5f81a830b8f1d8cb/stl/inc/thread) 代码进行讲解,新版 MSVC STL 的实现完全基于 **C++14**,所以即使是 C++11 引入的标准库设施,实现中可能也是使用到了 C++14 的东西。

## `std::thread` 的数据成员

- **了解一个庞大的类,最简单的方式就是先看它的数据成员有什么**。

`std::thread` 只保有一个私有数据成员 [`_Thr`](https://github.com/microsoft/STL/blob/main/stl/inc/thread#L163):
`std::thread` 只保有一个私有数据成员 [`_Thr`](https://github.com/microsoft/STL/blob/8e2d724cc1072b4052b14d8c5f81a830b8f1d8cb/stl/inc/thread#L163):

```cpp
private:
_Thrd_t _Thr;
```

[`_Thrd_t`](https://github.com/microsoft/STL/blob/main/stl/inc/xthreads.h#L22-L26) 是一个结构体,它保有两个数据成员:
[`_Thrd_t`](https://github.com/microsoft/STL/blob/8e2d724cc1072b4052b14d8c5f81a830b8f1d8cb/stl/inc/__msvc_threads_core.hpp#L20-L24) 是一个结构体,它保有两个数据成员:

```cpp
using _Thrd_id_t = unsigned int;
Expand Down Expand Up @@ -47,7 +47,7 @@ struct _Thrd_t { // thread identifier for Win32
thread(thread&& _Other) noexcept : _Thr(_STD exchange(_Other._Thr, {})) {}
```

[_STD](https://github.com/microsoft/STL/blob/main/stl/inc/yvals_core.h#L1951) 是一个宏,展开就是 `::std::`,也就是 [`::std::exchange`](https://zh.cppreference.com/w/cpp/utility/exchange),将 `_Other._Thr` 赋为 `{}` (也就是置空),返回 `_Other._Thr` 的旧值用以初始化当前对象的数据成员 `_Thr`。
[_STD](https://github.com/microsoft/STL/blob/8e2d724cc1072b4052b14d8c5f81a830b8f1d8cb/stl/inc/yvals_core.h#L1934) 是一个宏,展开就是 `::std::`,也就是 [`::std::exchange`](https://zh.cppreference.com/w/cpp/utility/exchange),将 `_Other._Thr` 赋为 `{}` (也就是置空),返回 `_Other._Thr` 的旧值用以初始化当前对象的数据成员 `_Thr`。

3. 复制构造函数被定义为弃置的,std::thread 不可复制。两个 std::thread 不可表示一个线程,std::thread 对线程资源是独占所有权。

Expand All @@ -68,7 +68,7 @@ struct _Thrd_t { // thread identifier for Win32

前三个构造函数都没啥要特别聊的,非常简单,只有第四个构造函数较为复杂,且是我们本章重点,需要详细讲解。(*注意 MSVC 使用标准库的内容很多时候不加 **std::**,脑补一下就行*)

如你所见,这个构造函数本身并没有做什么,它只是一个可变参数成员函数模板,增加了一些 [SFINAE](https://zh.cppreference.com/w/cpp/language/sfinae) 进行约束我们传入的[可调用](https://zh.cppreference.com/w/cpp/named_req/Callable)对象的类型不能是 `std::thread`。函数体中调用了一个函数 [**`_Start`**](https://github.com/microsoft/STL/blob/main/stl/inc/thread#L72-L87),将我们构造函数的参数全部完美转发,去调用它,这个函数才是我们的重点,如下:
如你所见,这个构造函数本身并没有做什么,它只是一个可变参数成员函数模板,增加了一些 [SFINAE](https://zh.cppreference.com/w/cpp/language/sfinae) 进行约束我们传入的[可调用](https://zh.cppreference.com/w/cpp/named_req/Callable)对象的类型不能是 `std::thread`。函数体中调用了一个函数 [**`_Start`**](https://github.com/microsoft/STL/blob/8e2d724cc1072b4052b14d8c5f81a830b8f1d8cb/stl/inc/thread#L72-L87),将我们构造函数的参数全部完美转发,去调用它,这个函数才是我们的重点,如下:

```cpp
template <class _Fn, class... _Args>
Expand Down Expand Up @@ -101,7 +101,7 @@ void _Start(_Fn&& _Fx, _Args&&... _Ax) {

4. `constexpr auto _Invoker_proc = _Get_invoke<_Tuple>(make_index_sequence<1 + sizeof...(_Args)>{})`

- 调用 [`_Get_invoke`](https://github.com/microsoft/STL/blob/main/stl/inc/thread#L65-L68) 函数,传入 `_Tuple` 类型和一个参数序列的索引序列(为了遍历形参包)。这个函数用于获取一个函数指针,指向了一个静态成员函数 [`_Invoke`](https://github.com/microsoft/STL/blob/main/stl/inc/thread#L55-L63),用来实际执行线程。这两个函数都非常的简单,我们来看看:
- 调用 [`_Get_invoke`](https://github.com/microsoft/STL/blob/8e2d724cc1072b4052b14d8c5f81a830b8f1d8cb/stl/inc/thread#L65-L68) 函数,传入 `_Tuple` 类型和一个参数序列的索引序列(为了遍历形参包)。这个函数用于获取一个函数指针,指向了一个静态成员函数 [`_Invoke`](https://github.com/microsoft/STL/blob/8e2d724cc1072b4052b14d8c5f81a830b8f1d8cb/stl/inc/thread#L55-L63),用来实际执行线程。这两个函数都非常的简单,我们来看看:

```cpp
template <class _Tuple, size_t... _Indices>
Expand Down
2 changes: 1 addition & 1 deletion md/详细分析/02scoped_lock源码解析.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

这会涉及到不少的模板技术,这没办法,就如同我们先前聊 [`std::thread` 的构造与源码分析](01thread的构造与源码解析.md)最后说的:“**不会模板,你阅读标准库源码,是无稽之谈**”。

我们还是一样的,以 MSVC STL 的实现的 [`std::scoped_lock`](https://github.com/microsoft/STL/blob/main/stl/inc/mutex#L476-L528) 代码进行讲解,不用担心,我们也查看了 [`libstdc++`](https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/std/mutex#L743-L802) 、[`libc++`](https://github.com/llvm/llvm-project/blob/main/libcxx/include/mutex#L424-L488)的实现,并没有太多区别,更多的是一些风格上的。而且个人觉得 MSVC 的实现是最简单直观的。
我们还是一样的,以 MSVC STL 的实现的 [`std::scoped_lock`](https://github.com/microsoft/STL/blob/8e2d724cc1072b4052b14d8c5f81a830b8f1d8cb/stl/inc/mutex#L476-L528) 代码进行讲解,不用担心,我们也查看了 [`libstdc++`](https://github.com/gcc-mirror/gcc/blob/7a01cc711f33530436712a5bfd18f8457a68ea1f/libstdc%2B%2B-v3/include/std/mutex#L743-L802) 、[`libc++`](https://github.com/llvm/llvm-project/blob/7ac7d418ac2b16fd44789dcf48e2b5d73de3e715/libcxx/include/mutex#L424-L488)的实现,并没有太多区别,更多的是一些风格上的。而且个人觉得 MSVC 的实现是最简单直观的。

## `std:scoped_lock` 的数据成员

Expand Down