@@ -44,7 +44,7 @@ int main(){
44
44
45
45
## 当前环境支持并发线程数
46
46
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 ` 的静态成员函数。
48
48
49
49
``` cpp
50
50
#include < iostream>
@@ -56,9 +56,9 @@ int main(){
56
56
}
57
57
```
58
58
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 ) ** ”。
60
60
61
- > 英特尔® 超线程技术是一项硬件创新 ,允许在每个内核上运行多个线程。更多的线程意味着可以** 并行** 完成更多的工作。
61
+ > [ 英特尔® 超线程 ] ( https://www.intel.cn/content/www/cn/zh/gaming/resources/hyper-threading.html ) 技术是一项硬件创新 ,允许在每个内核上运行多个线程。更多的线程意味着可以** 并行** 完成更多的工作。
62
62
>
63
63
> AMD 超线程技术被称为 SMT(Simultaneous Multi-Threading),它与英特尔的技术实现有所不同,不过使用类似。
64
64
@@ -68,9 +68,9 @@ int main(){
68
68
69
69
当然了,都 2024 年了,我们还得考虑一个问题:“ * 英特尔从 12 代酷睿开始,为其处理器引入了全新的“** 大小核** ”混合设计架构* ”。
70
70
71
- 比如我的 CPU ` i7 13700H ` 它是 14 核心,20 线程,有 6 个能效核,6 个性能核。不过我们说了,物理核心这个通常不看重 ,` hardware_concurrency() ` 输出的值会为 20。
71
+ 比如我的 CPU ` i7 13700H ` 它是 14 核心,20 线程,有 6 个能效核,6 个性能核。不过我们说了,物理核心这个 * 通常 * 不看重 ,` hardware_concurrency() ` 输出的值会为 20。
72
72
73
- - ** 在进行多线程编程的时候,我们可以参考此值确定我们要创建的线程数量 **
73
+ - ** 在进行多线程编程时,我们可以参考此值来确定创建的线程数量,以更好地利用当前硬件,从而提升程序性能。 **
74
74
75
75
---
76
76
@@ -157,7 +157,7 @@ typename std::iterator_traits<ForwardIt>::value_type sum(ForwardIt first, Forwar
157
157
158
158
## 线程管理
159
159
160
- 在 C++ 标准库中,只能管理与 ` std::thread ` 关联的线程, 类 ` std::thread ` 的对象就是指代线程的对象,我们说 “线程管理”,其实也就是管理 ` std::thread ` 对象。
160
+ 在 C++ 标准库中,没有直接管理线程的机制,只能通过对象关联线程后,通过该对象来管理线程。 类 ` std::thread ` 的对象就是指代线程的对象,而我们本节说的 “线程管理”,其实也就是指管理 ` std::thread ` 对象。
161
161
162
162
### 启动新线程
163
163
@@ -351,7 +351,7 @@ void f(){
351
351
352
352
“[资源获取即初始化](https://zh.cppreference.com/w/cpp/language/raii)”(RAII,Resource Acquisition Is Initialization)。
353
353
354
- 简单的说是:***构造函数申请资源,析构函数释放资源,让对象的生命周期和资源绑定***。当异常抛出时,C++ 会自动调用栈上所有对象的析构函数 。
354
+ 简单的说是:***构造函数申请资源,析构函数释放资源,让对象的生命周期和资源绑定***。当异常抛出时,C++ 会自动调用对象的析构函数 。
355
355
356
356
我们可以提供一个类,在析构函数中使用 join() 确保线程执行完成,线程对象正常析构。
357
357
@@ -674,7 +674,7 @@ void test(){
674
674
675
675
传入可调用对象以及参数,构造 ` std::thread ` 对象,启动线程,而线程对象拥有了线程的所有权,线程是一种系统资源,所以可称作“* 线程资源* ”。
676
676
677
- std::thread 不可复制。两个 std::thread 不可表示一个线程 ,std::thread 对线程资源是独占所有权。移动就是转移它的线程资源的所有权给别的 ` std::thread ` 对象。
677
+ std::thread 不可复制。两个 std::thread 对象不可表示一个线程 ,std::thread 对线程资源是独占所有权。而 ** 移动 ** 操作可以将一个 ` std::thread ` 对象的线程资源所有权转移给另一个 ` std::thread ` 对象。
678
678
679
679
``` cpp
680
680
int main () {
@@ -723,11 +723,11 @@ int main(){
723
723
}
724
724
```
725
725
726
- 这段代码可以[ 通过编译] ( https://godbolt.org/z/14d7b9qn9 ) ,你是否感到奇怪?我们在函数 f() 中创建了一个局部的 ` std::thread ` 对象,启动线程,然后返回它。
726
+ 这段代码可以[ 通过编译] ( https://godbolt.org/z/14d7b9qn9 ) ,你是否感到奇怪?我们在函数 f 中创建了一个局部的 ` std::thread ` 对象,启动线程,然后返回它。
727
727
728
728
这里的 ` return t ` * 重载决议* [ ^ 1 ] 选择到了** 移动构造** ,将 ` t ` 线程资源的所有权转移给函数调用 ` f() ` 返回的临时 ` std::thread ` 对象中,然后这个临时对象再用来初始化 ` rt ` ,临时对象是右值表达式,这里一样选择到** 移动构造** ,将临时对象的线程资源所有权移交给 ` rt ` 。此时 ` rt ` 具有线程资源的所有权,由它调用 ` join() ` 正常析构。
729
729
730
- > 如果标准达到 C++17,RVO 保证这里少一次移动构造的开销(临时对象初始化 ` rt ` 的这次)。
730
+ > 如果标准达到 C++17,强制的复制消除( RVO) 保证这里少一次移动构造的开销(临时对象初始化 ` rt ` 的这次)。
731
731
732
732
** 所有权也可以在函数内部传递** :
733
733
@@ -751,9 +751,18 @@ int main(){
751
751
752
752
## [`std::thread` 的构造-源码解析](详细分析/01thread的构造与源码解析.md)
753
753
754
- 我们上一个大节讲解了线程管理,也就是 `std::thread` 的管理 ,其中的重中之重就是它的构造,传递参数。我们用源码实现为各位从头讲解。
754
+ 我们上一个大节讲解了线程管理,也就是 `std::thread` 的使用 ,其中的重中之重就是它的构造,传递参数。我们用源码实现为各位从头讲解。
755
755
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) 后,可以再回过头来问问自己是否能够回答这些问题。
757
766
758
767
## 实现 `joining_thread`
759
768
@@ -859,8 +868,8 @@ int main(){
859
868
860
869
## 总结
861
870
862
- 本章节的内容围绕着:“使用线程”,也就是"** 使用 ` std::thread ` ** "展开, ` std::thread ` 是我们学习 C++ 并发支持库的重中之重,本章的内容并不少见 ,但是却是少有的准确与完善。即使你早已学习过乃至使用 C++ 标准库进行多线程编程已经很久 ,我相信本章也一定可以让你收获良多。
871
+ 本章节的内容围绕着:“使用线程”,也就是"** 使用 ` std::thread ` ** "展开, ` std::thread ` 是我们学习 C++ 并发支持库的重中之重,本章的内容在市面上并不少见 ,但是却是少有的准确与完善。即使你早已学习乃至使用 C++ 标准库进行多线程编程 ,我相信本章也一定可以让你收获良多。
863
872
864
- 如果是第一次学习,有还不够理解的地方,则一定要多思考,或记住,以后多看 。
873
+ 如果是第一次学习本章的内容,能会有一些难以理解的地方。建议你多思考、多记忆,并在以后反复查看和实践 。
865
874
866
- 我尽量讲的简单与通俗易懂。学完本章,你大概率还无法在实际环境使用多线程提升程序效率,至少也要学习到使用互斥量,保护共享数据,才可实际使用 。
875
+ 我尽量以简单通俗的方式进行讲解。学完本章后,你可能还无法在实际环境利用多线程提升程序效率,至少还需要学习到使用互斥量来保护共享数据,才能实际应用多线程编程 。
0 commit comments