Skip to content

Commit 56d42a6

Browse files
committed
1. 更新 SUMMARY 文件,目录
2. 修改第二章的一些措辞与描述,增加一些超链接 3. 修改第三章“条件竞争”一节中第一个示例的描述,无需强调“单个”,`operator<<` 函数是线程安全,自然调用是线程安全。即使多个调用那也是有交错无竞争,无需其它措辞影响含义。
1 parent 769cd53 commit 56d42a6

File tree

4 files changed

+29
-18
lines changed

4 files changed

+29
-18
lines changed

SUMMARY.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
* [使用线程](md/02使用线程.md)
66
* [共享数据](md/03共享数据.md)
77
* [同步操作](md/04同步操作.md)
8+
* [内存模型与原子操作](md/05内存模型与原子操作.md)
9+
* [协程](md/06协程.md)
810
* [详细分析](md/详细分析/README.md)
911
* [`std::thread` 的构造-源码解析](md/详细分析/01thread的构造与源码解析.md)
1012
* [`std::scoped_lock` 的源码实现与解析](md/详细分析/02scoped_lock源码解析.md)

md/02使用线程.md

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ int main(){
4444

4545
## 当前环境支持并发线程数
4646

47-
使用 [`hardware_concurrency`](https://zh.cppreference.com/w/cpp/thread/thread/hardware_concurrency) 可以获得我们当前硬件支持的并发线程数量,它是 `std::thread` 的静态成员函数。
47+
使用 [`hardware_concurrency`](https://zh.cppreference.com/w/cpp/thread/thread/hardware_concurrency) 函数可以获得我们当前硬件支持的并发线程数量,它是 `std::thread` 的静态成员函数。
4848

4949
```cpp
5050
#include <iostream>
@@ -56,9 +56,9 @@ int main(){
5656
}
5757
```
5858

59-
本节其实是要普及一下计算机常识,一些古老的书籍比如 csapp 应该也会提到“**[超线程技术](https://www.intel.cn/content/www/cn/zh/gaming/resources/hyper-threading.html)**”。
59+
本节其实是要普及一下计算机常识,一些古老的书籍比如 [csapp](https://hansimov.gitbook.io/csapp/ch01-a-tour-of-computer-systems/1.9#id-1.-xian-cheng-ji-bing-fa) 应该也会提到“**[超线程技术](https://www.intel.cn/content/www/cn/zh/gaming/resources/hyper-threading.html)**”。
6060

61-
> 英特尔® 超线程技术是一项硬件创新,允许在每个内核上运行多个线程。更多的线程意味着可以**并行**完成更多的工作。
61+
> [英特尔® 超线程](https://www.intel.cn/content/www/cn/zh/gaming/resources/hyper-threading.html)技术是一项硬件创新,允许在每个内核上运行多个线程。更多的线程意味着可以**并行**完成更多的工作。
6262
>
6363
> AMD 超线程技术被称为 SMT(Simultaneous Multi-Threading),它与英特尔的技术实现有所不同,不过使用类似。
6464
@@ -68,9 +68,9 @@ int main(){
6868

6969
当然了,都 2024 年了,我们还得考虑一个问题:“ *英特尔从 12 代酷睿开始,为其处理器引入了全新的“**大小核**”混合设计架构*”。
7070

71-
比如我的 CPU `i7 13700H` 它是 14 核心,20 线程,有 6 个能效核,6 个性能核。不过我们说了,物理核心这个通常不看重`hardware_concurrency()` 输出的值会为 20。
71+
比如我的 CPU `i7 13700H` 它是 14 核心,20 线程,有 6 个能效核,6 个性能核。不过我们说了,物理核心这个*通常*不看重`hardware_concurrency()` 输出的值会为 20。
7272

73-
- **在进行多线程编程的时候,我们可以参考此值确定我们要创建的线程数量**
73+
- **在进行多线程编程时,我们可以参考此值来确定创建的线程数量,以更好地利用当前硬件,从而提升程序性能。**
7474

7575
---
7676

@@ -157,7 +157,7 @@ typename std::iterator_traits<ForwardIt>::value_type sum(ForwardIt first, Forwar
157157

158158
## 线程管理
159159

160-
在 C++ 标准库中,只能管理与 `std::thread` 关联的线程,`std::thread` 的对象就是指代线程的对象,我们说“线程管理”,其实也就是管理 `std::thread` 对象。
160+
在 C++ 标准库中,没有直接管理线程的机制,只能通过对象关联线程后,通过该对象来管理线程。`std::thread` 的对象就是指代线程的对象,而我们本节说的“线程管理”,其实也就是指管理 `std::thread` 对象。
161161

162162
### 启动新线程
163163

@@ -351,7 +351,7 @@ void f(){
351351
352352
“[资源获取即初始化](https://zh.cppreference.com/w/cpp/language/raii)”(RAII,Resource Acquisition Is Initialization)。
353353
354-
简单的说是:***构造函数申请资源,析构函数释放资源,让对象的生命周期和资源绑定***。当异常抛出时,C++ 会自动调用栈上所有对象的析构函数
354+
简单的说是:***构造函数申请资源,析构函数释放资源,让对象的生命周期和资源绑定***。当异常抛出时,C++ 会自动调用对象的析构函数
355355
356356
我们可以提供一个类,在析构函数中使用 join() 确保线程执行完成,线程对象正常析构。
357357
@@ -674,7 +674,7 @@ void test(){
674674
675675
传入可调用对象以及参数,构造 `std::thread` 对象,启动线程,而线程对象拥有了线程的所有权,线程是一种系统资源,所以可称作“*线程资源*”。
676676
677-
std::thread 不可复制。两个 std::thread 不可表示一个线程,std::thread 对线程资源是独占所有权。移动就是转移它的线程资源的所有权给别的 `std::thread` 对象。
677+
std::thread 不可复制。两个 std::thread 对象不可表示一个线程,std::thread 对线程资源是独占所有权。**移动**操作可以将一个 `std::thread` 对象的线程资源所有权转移给另一个 `std::thread` 对象。
678678
679679
```cpp
680680
int main() {
@@ -723,11 +723,11 @@ int main(){
723723
}
724724
```
725725
726-
这段代码可以[通过编译](https://godbolt.org/z/14d7b9qn9),你是否感到奇怪?我们在函数 f() 中创建了一个局部的 `std::thread` 对象,启动线程,然后返回它。
726+
这段代码可以[通过编译](https://godbolt.org/z/14d7b9qn9),你是否感到奇怪?我们在函数 f 中创建了一个局部的 `std::thread` 对象,启动线程,然后返回它。
727727
728728
这里的 `return t` *重载决议*[^1]选择到了**移动构造**,将 `t` 线程资源的所有权转移给函数调用 `f()` 返回的临时 `std::thread` 对象中,然后这个临时对象再用来初始化 `rt` ,临时对象是右值表达式,这里一样选择到**移动构造**,将临时对象的线程资源所有权移交给 `rt`。此时 `rt` 具有线程资源的所有权,由它调用 `join()` 正常析构。
729729
730-
> 如果标准达到 C++17,RVO 保证这里少一次移动构造的开销(临时对象初始化 `rt` 的这次)。
730+
> 如果标准达到 C++17,强制的复制消除(RVO保证这里少一次移动构造的开销(临时对象初始化 `rt` 的这次)。
731731
732732
**所有权也可以在函数内部传递**
733733
@@ -751,9 +751,18 @@ int main(){
751751
752752
## [`std::thread` 的构造-源码解析](详细分析/01thread的构造与源码解析.md)
753753
754-
我们上一个大节讲解了线程管理,也就是 `std::thread` 的管理,其中的重中之重就是它的构造,传递参数。我们用源码实现为各位从头讲解。
754+
我们上一个大节讲解了线程管理,也就是 `std::thread` 的使用,其中的重中之重就是它的构造,传递参数。我们用源码实现为各位从头讲解。
755755
756-
了解其实现,才能更好的使用它。
756+
了解其实现,才能更好的使用它,同时也能解释其使用与学习中的各种问题。如:
757+
758+
- 为什么默认复制?
759+
- 为什么需要 `std::ref` ?
760+
- 如何支持只能移动的对象?
761+
- 如何做到接受任意[可调用](https://zh.cppreference.com/w/cpp/named_req/Callable)对象?
762+
- 如何创建的线程?
763+
- [传递参数](#传递参数)一节中的:“*`std::thread` 内部会将保有的参数副本转换为**右值表达式进行传递***”到底是如何做到的?
764+
765+
当你看完 [**`std::thread` 的构造-源码解析**](详细分析/01thread的构造与源码解析.md) 后,可以再回过头来问问自己是否能够回答这些问题。
757766
758767
## 实现 `joining_thread`
759768
@@ -859,8 +868,8 @@ int main(){
859868
860869
## 总结
861870
862-
本章节的内容围绕着:“使用线程”,也就是"**使用 `std::thread`**"展开, `std::thread` 是我们学习 C++ 并发支持库的重中之重,本章的内容并不少见,但是却是少有的准确与完善。即使你早已学习过乃至使用 C++ 标准库进行多线程编程已经很久,我相信本章也一定可以让你收获良多。
871+
本章节的内容围绕着:“使用线程”,也就是"**使用 `std::thread`**"展开, `std::thread` 是我们学习 C++ 并发支持库的重中之重,本章的内容在市面上并不少见,但是却是少有的准确与完善。即使你早已学习乃至使用 C++ 标准库进行多线程编程,我相信本章也一定可以让你收获良多。
863872
864-
如果是第一次学习,有还不够理解的地方,则一定要多思考,或记住,以后多看
873+
如果是第一次学习本章的内容,能会有一些难以理解的地方。建议你多思考、多记忆,并在以后反复查看和实践
865874
866-
我尽量讲的简单与通俗易懂。学完本章,你大概率还无法在实际环境使用多线程提升程序效率,至少也要学习到使用互斥量,保护共享数据,才可实际使用
875+
我尽量以简单通俗的方式进行讲解。学完本章后,你可能还无法在实际环境利用多线程提升程序效率,至少还需要学习到使用互斥量来保护共享数据,才能实际应用多线程编程

md/03共享数据.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ int main(){
2828
}
2929
```
3030

31-
> [`std::cout`](https://zh.cppreference.com/w/cpp/io/cout) 的单个 operator<< 调用是线程安全的,不会被打断。即:*同步的 C++ 流保证是线程安全的(从多个线程输出的单独字符可能交错,但无数据竞争)*
31+
> [`std::cout`](https://zh.cppreference.com/w/cpp/io/cout) operator<< 调用是线程安全的,不会被打断。即:*同步的 C++ 流保证是线程安全的(从多个线程输出的单独字符可能交错,但无数据竞争)*
3232
33-
只有在涉及多线程修改相同共享数据的时候,才会导致“*恶性的条件竞争*”。
33+
只有在涉及多线程读写相同共享数据的时候,才会导致“*恶性的条件竞争*”。
3434

3535
```cpp
3636
std::vector<int>v;

md/05内存模型与原子操作.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,4 +344,4 @@ print("end"); // 2
344344

345345
不禁止就是有可能,但是我们无需在乎,**就算真的 CPU 将 end 重排到 start 前面了,也得在可观测行为发生前回溯了**。所以我一直在强调,这些东西,**我们无需在意**
346346

347-
好了,到此,基本认识也就足够了,这些还是简单直接且符合直觉的。
347+
好了,到此,基本认识也就足够了以上的示例更多的是泛指,知到其表达的意思就好,这些还是简单直接且符合直觉的。

0 commit comments

Comments
 (0)