Skip to content

Commit a810f7b

Browse files
committed
修改部分措辞以及增加描述
1 parent 1bfbf00 commit a810f7b

File tree

3 files changed

+9
-7
lines changed

3 files changed

+9
-7
lines changed

md/03共享数据.md

+5-3
Original file line numberDiff line numberDiff line change
@@ -692,7 +692,7 @@ void process_data(){
692692
693693
以上代码 `std::once_flag` 对象是全局命名空间作用域声明,如果你有需要,它也可以是类的成员。用于搭配 `std::call_once` 使用,保证线程安全的**一次**初始化。`std::call_once` 只需要接受[*可调用 (Callable)*](https://zh.cppreference.com/w/cpp/named_req/Callable)对象即可,也不要求一定是函数。
694694
695-
>**初始化**”,自然是**一次**。但是 `std::call_once` 也有一些例外情况(比如异常)会让传入的可调用对象被多次调用,即“**多次**”初始化:
695+
>**初始化**”,那自然是只有**一次**。但是 `std::call_once` 也有一些例外情况(比如异常)会让传入的可调用对象被多次调用,即“**多次**”初始化:
696696
>
697697
> ```cpp
698698
> std::once_flag flag;
@@ -720,6 +720,8 @@ void process_data(){
720720
> ```
721721
>
722722
> [测试链接](https://godbolt.org/z/aWqfEchd6)。正常情况会保证传入的可调用对象只调用一次,即初始化只有一次。异常之类的是例外。
723+
>
724+
>这种行为很合理,因为异常代表操作失败,需要进行回溯和重置状态,符合语义和设计。
723725
724726
3. **静态局部变量初始化在 C++11 是线程安全**
725727
@@ -735,7 +737,7 @@ void process_data(){
735737
736738
---
737739
738-
其实还有不少其他的做法或者反例,但是觉得没必要再聊了,因为本文不是详尽的文档,而是“**教程**”。
740+
其实还有不少其他的做法或者反例,但是觉得没必要再聊了,这些已经足够了,再多下去就冗余了。且本文不是详尽的文档,而是“**教程**”。
739741
740742
## 保护不常更新的数据结构
741743
@@ -898,7 +900,7 @@ C++ 只保证了 `operator new`、`operator delete` 这两个方面的线程安
898900
899901
**线程存储期**(也有人喜欢称作“[*线程局部存储*](https://zh.wikipedia.org/wiki/%E7%BA%BF%E7%A8%8B%E5%B1%80%E9%83%A8%E5%AD%98%E5%82%A8)”)的概念源自操作系统,是一种非常古老的机制,广泛应用于各种编程语言。线程存储期的对象在线程开始时分配,并在线程结束时释放。每个线程拥有自己独立的对象实例,互不干扰。在 C++11中,引入了[**`thread_local`**](https://zh.cppreference.com/w/cpp/keyword/thread_local)关键字,用于声明具有线程存储期的对象。
900902
901-
以下是一个示例代码,展示了 `thread_local` 关键字的使用:
903+
以下是一段示例代码,展示了 `thread_local` 关键字的使用:
902904
903905
```cpp
904906
int global_counter = 0;

md/04同步操作.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -720,9 +720,9 @@ _Ty& get() {
720720
}
721721
```
722722

723-
如上所示,我们展示了 `std::future` 的所有特化 `get` 成员函数的实现。注意到了吗?尽管我们可能不了解移动构造函数的具体实现,但根据通用的语义,可以看出 `future _Local{_STD move(*this)};` 将当前对象的共享状态转移给了这个局部对象,而局部对象在函数结束时析构。这意味着当前对象失去共享状态,并且状态被完全销毁。
723+
如上所示,我们展示了 `std::future` 的所有特化中 `get` 成员函数的实现。注意到了吗?尽管我们可能不了解移动构造函数的具体实现,但根据通用的语义,可以看出 `future _Local{_STD move(*this)};` 将当前对象的共享状态转移给了这个局部对象,而局部对象在函数结束时析构。这意味着当前对象失去共享状态,并且状态被完全销毁。
724724

725-
另外一提,`std::future<T>` 这个特化,它 `return std::move` 是为了支持只能移动的类型能够使用 `get` 返回值,参见前文的 `move_only` 类型。
725+
另外一提,`std::future<T>` 这个特化,它 `return std::move` 是为了**支持只能移动的类型**能够使用 `get` 返回值,参见前文的 `move_only` 类型。
726726

727727
如果需要进行多次 `get` 调用,可以考虑使用下文提到的 `std::shared_future`
728728

@@ -1229,7 +1229,7 @@ int main() {
12291229

12301230
---
12311231

1232-
信号量常用于发信/提醒而非互斥,通过初始化该信号量为 0 从而阻塞尝试 acquire() 的接收者,直至提醒者通过调用 release(n) “发信”。在此方面可把信号量当作**条件变量的替代品****通常它有更好的性能**
1232+
信号量常用于*发信/提醒*而非互斥,通过初始化该信号量为 0 从而阻塞尝试 acquire() 的接收者,直至提醒者通过调用 release(n) “发信”。在此方面可把信号量当作**条件变量的替代品****通常它有更好的性能**
12331233

12341234
假设我们有一个 Web 服务器,它只能处理有限数量的并发请求。为了防止服务器过载,我们可以**使用信号量来限制并发请求的数量**
12351235

md/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
## 学习注意事项
1010

11-
&emsp;&emsp;我们的教程中常包含许多外部链接,这并非当前描述不足或者不够严谨,而是为了考虑读者的水平和可能的扩展学习需求。同时,也希望者能让读者避免获取二手知识与理解,我们提供的链接基本都是较为专业的文档或官方网站。
11+
&emsp;&emsp;我们的教程中常包含许多外部链接,这并非当前描述不足或者不够严谨,而是为了考虑读者的水平和可能的扩展学习需求。同时,也希望能让读者避免获取二手知识与理解,我们提供的链接基本都是较为专业的文档或官方网站。
1212

1313
&emsp;&emsp;虽然教程名为《现代 C++ 并发编程教程》,但我们也扩展涉及了许多其他知识,包括但不限于:Win32、POSIX API;MSVC STL、libstdc++、libc++ 对标准库的实现;GCC 与 MSVC 的编译器扩展,以及 Clang 对它们的兼容;使用 CMake + Qt 构建带 UI 的程序,展示多线程异步的必要性;不同架构的内存模型(例如 x86 架构内存模型:Total Store Order (TSO),较为严格的内存模型)。
1414

0 commit comments

Comments
 (0)