From a1c4184b8dae37bbeaa250a5b6d996fd29772655 Mon Sep 17 00:00:00 2001 From: Yikai Cai <35102736+VVsxmja@users.noreply.github.com> Date: Tue, 6 Dec 2022 15:35:38 +0800 Subject: [PATCH 01/14] book: style fixes (#256) --- book/zh-cn/03-runtime.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/zh-cn/03-runtime.md b/book/zh-cn/03-runtime.md index a8ce6d85..12894127 100644 --- a/book/zh-cn/03-runtime.md +++ b/book/zh-cn/03-runtime.md @@ -249,7 +249,7 @@ const char*&& pr = "01234"; // 正确,"01234" 被隐式转换为 const char* // const char*& pl = "01234"; // 错误,此处不存在 const char* 类型的左值 ``` -**将亡值(xvalue, expiring value)**,是 C++11 为了引入右值引用而提出的概念(因此在传统 C++ 中, +**将亡值** (xvalue, expiring value),是 C++11 为了引入右值引用而提出的概念(因此在传统 C++ 中, 纯右值和右值是同一个概念),也就是即将被销毁、却能够被移动的值。 将亡值可能稍有些难以理解,我们来看这样的代码: From 4228ff2afb2b7fd829c460e2d67e084e191ec23d Mon Sep 17 00:00:00 2001 From: David Date: Fri, 30 Dec 2022 17:29:50 +0800 Subject: [PATCH 02/14] book: type fix (#257) --- book/en-us/02-usability.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/en-us/02-usability.md b/book/en-us/02-usability.md index 10c13ffa..3528c68a 100644 --- a/book/en-us/02-usability.md +++ b/book/en-us/02-usability.md @@ -548,7 +548,7 @@ std::cout << "q: " << q << std::endl; > To understand it you need to know the concept of parameter forwarding > in C++, which we will cover in detail in the -> [Language Runtime Hardening](./03-runtime.md) chapter, +> [Language Runtime Enhancements](./03-runtime.md) chapter, > and you can come back to the contents of this section later. In simple terms, `decltype(auto)` is mainly used to derive From 725df6b753b02a0bcffb52b79c52ef2bd67470c8 Mon Sep 17 00:00:00 2001 From: Guo Shuai Date: Mon, 27 Feb 2023 14:29:37 +0800 Subject: [PATCH 03/14] book: wording (#260) --- book/zh-cn/07-thread.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/zh-cn/07-thread.md b/book/zh-cn/07-thread.md index d6b08fd1..8e11407d 100644 --- a/book/zh-cn/07-thread.md +++ b/book/zh-cn/07-thread.md @@ -11,7 +11,7 @@ order: 7 ## 7.1 并行基础 `std::thread` 用于创建一个执行的线程实例,所以它是一切并发编程的基础,使用时需要包含 `` 头文件, -它提供了很多基本的线程操作,例如 `get_id()` 来获取所创建线程的线程 ID,使用 `join()` 来加入一个线程等等,例如: +它提供了很多基本的线程操作,例如 `get_id()` 来获取所创建线程的线程 ID,使用 `join()` 来等待一个线程结束(与该线程汇合)等等,例如: ```cpp #include From eca0b923075f1e71830a55ddaadc5f8bc44d17a1 Mon Sep 17 00:00:00 2001 From: GNAQ <41422940+GNAQ@users.noreply.github.com> Date: Tue, 7 Mar 2023 17:28:52 +0800 Subject: [PATCH 04/14] book: style fixes (#261) --- book/zh-cn/00-preface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/zh-cn/00-preface.md b/book/zh-cn/00-preface.md index ec04257d..5e26f70e 100644 --- a/book/zh-cn/00-preface.md +++ b/book/zh-cn/00-preface.md @@ -11,7 +11,7 @@ order: 0 ## 引言 C++ 是一个用户群体相当大的语言。从 C++98 的出现到 C++11 的正式定稿经历了长达十年多之久的积累。C++14/17 则是作为对 C++11 的重要补充和优化,C++20 则将这门语言领进了现代化的大门,所有这些新标准中扩充的特性,给 C++ 这门语言注入了新的活力。 -那些还在坚持使用**传统 C++**(本书把 C++98 及其之前的 C++ 特性均称之为传统 C++)而未接触过现代 C++ 的 C++ 程序员在见到诸如 Lambda 表达式这类全新特性时,甚至会流露出『学的不是同一门语言』的惊叹之情。 +那些还在坚持使用**传统 C++** (本书把 C++98 及其之前的 C++ 特性均称之为传统 C++)而未接触过现代 C++ 的 C++ 程序员在见到诸如 Lambda 表达式这类全新特性时,甚至会流露出『学的不是同一门语言』的惊叹之情。 **现代 C++** (本书中均指 C++11/14/17/20) 为传统 C++ 注入的大量特性使得整个 C++ 变得更加像一门现代化的语言。现代 C++ 不仅仅增强了 C++ 语言自身的可用性,`auto` 关键字语义的修改使得我们更加有信心来操控极度复杂的模板类型。同时还对语言运行期进行了大量的强化,Lambda 表达式的出现让 C++ 具有了『匿名函数』的『闭包』特性,而这一特性几乎在现代的编程语言(诸如 Python/Swift/... )中已经司空见惯,右值引用的出现解决了 C++ 长期以来被人诟病的临时对象效率问题等等。 From e86e4a4b94b5dbc691688fa61c4264934898524b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A5=9D=E7=8D=BB=E7=9A=84=E5=B7=B4=E5=9F=BA=E5=8A=9B?= <68413810+Valkierja@users.noreply.github.com> Date: Sun, 7 May 2023 03:17:04 +0800 Subject: [PATCH 05/14] book: typo fixes (#262) --- book/zh-cn/03-runtime.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/book/zh-cn/03-runtime.md b/book/zh-cn/03-runtime.md index 12894127..1760b3a8 100644 --- a/book/zh-cn/03-runtime.md +++ b/book/zh-cn/03-runtime.md @@ -523,8 +523,8 @@ static_cast 传参: 右值引用 static_cast 传参: 左值引用 ``` -无论传递参数为左值还是右值,普通传参都会将参数作为左值进行转发, -所以 `std::move` 总会接受到一个左值,从而转发调用了`reference(int&&)` 输出右值引用。 +无论传递参数为左值还是右值,普通传参都会将参数作为左值进行转发; +由于类似的原因,`std::move` 总会接受到一个左值,从而转发调用了`reference(int&&)` 输出右值引用。 唯独 `std::forward` 即没有造成任何多余的拷贝,同时**完美转发**(传递)了函数的实参给了内部调用的其他函数。 From ff6ee89e2a5b16e0ec2342a61171086187fd3a8b Mon Sep 17 00:00:00 2001 From: lingkerio whiher <112792583+lingkerio@users.noreply.github.com> Date: Sun, 7 May 2023 15:19:09 +0800 Subject: [PATCH 06/14] book: discriminative modification to the nature of override and overload (#265) --- book/en-us/02-usability.md | 2 +- book/zh-cn/02-usability.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/book/en-us/02-usability.md b/book/en-us/02-usability.md index 3528c68a..6da7d8e5 100644 --- a/book/en-us/02-usability.md +++ b/book/en-us/02-usability.md @@ -971,7 +971,7 @@ C++11 introduces the two keywords `override` and `final` to prevent this from ha ### override -When overriding a virtual function, introducing the `override` keyword will explicitly tell the compiler to overload, and the compiler will check if the base function has such a virtual function, otherwise it will not compile: +When overriding a virtual function, introducing the `override` keyword will explicitly tell the compiler to overload, and the compiler will check if the base function has such a virtual function with consistent function signature, otherwise it will not compile: ```cpp struct Base { diff --git a/book/zh-cn/02-usability.md b/book/zh-cn/02-usability.md index d7193dd4..ed4fe982 100644 --- a/book/zh-cn/02-usability.md +++ b/book/zh-cn/02-usability.md @@ -880,7 +880,7 @@ C++11 引入了 `override` 和 `final` 这两个关键字来防止上述情形 #### override -当重载虚函数时,引入 `override` 关键字将显式的告知编译器进行重载,编译器将检查基函数是否存在这样的虚函数,否则将无法通过编译: +当重载虚函数时,引入 `override` 关键字将显式的告知编译器进行重载,编译器将检查基函数是否存在这样的其函数签名一致的虚函数,否则将无法通过编译: ```cpp struct Base { From bdf0e899a7f9619acba31f8c5eee15bb2d6c6324 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Tue, 21 May 2024 05:53:15 +0800 Subject: [PATCH 07/14] book: fix imprecise description of `NULL` in C++ (#279) --- book/en-us/02-usability.md | 17 +++++++++-------- book/zh-cn/02-usability.md | 4 ++-- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/book/en-us/02-usability.md b/book/en-us/02-usability.md index 6da7d8e5..51d3edcf 100644 --- a/book/en-us/02-usability.md +++ b/book/en-us/02-usability.md @@ -18,20 +18,21 @@ which refers to the language behavior that occurred before the runtime. ### nullptr -The purpose of `nullptr` appears to replace `NULL`. In a sense, -traditional C++ treats `NULL` and `0` as the same thing, -depending on how the compiler defines NULL, -and some compilers define NULL as `((void*)0)` Some will define it directly as `0`. +The purpose of `nullptr` appears to replace `NULL`. There are **null pointer constants** in the C and C++ languages, +which can be implicitly converted to null pointer value of any pointer type, +or null member pointer value of any pointer-to-member type in C++. +`NULL` is provided by the standard library implementation and defined as an implementation-defined null pointer constant. +In C, some standard libraries defines `NULL` as `((void*)0)` and some define it as `0`. -C++ **does not allow** to implicitly convert `void *` to other types. -But if the compiler tries to define `NULL` as `((void*)0)`, then in the following code: +C++ **does not allow** to implicitly convert `void *` to other types, and thus `((void*)0)` is not a valid implementation +of `NULL`. If the standard library tries to define `NULL` as `((void*)0)`, then compilation error would occur in the following code: ```cpp char *ch = NULL; ``` C++ without the `void *` implicit conversion has to define `NULL` as `0`. -This still creates a new problem. Defining `NULL` to 0 will cause the overloading feature in `C++` to be confusing. +This still creates a new problem. Defining `NULL` to `0` will cause the overloading feature in `C++` to be confusing. Consider the following two `foo` functions: ```cpp @@ -41,7 +42,7 @@ void foo(int); Then the `foo(NULL);` statement will call `foo(int)`, which will cause the code to be counterintuitive. -To solve this problem, C++11 introduced the `nullptr` keyword, which is specifically used to distinguish null pointers, 0. The type of `nullptr` is `nullptr_t`, which can be implicitly converted to any pointer or member pointer type, and can be compared equally or unequally with them. +To solve this problem, C++11 introduced the `nullptr` keyword, which is specifically used to distinguish null pointers, `0`. The type of `nullptr` is `nullptr_t`, which can be implicitly converted to any pointer or member pointer type, and can be compared equally or unequally with them. You can try to compile the following code using clang++: diff --git a/book/zh-cn/02-usability.md b/book/zh-cn/02-usability.md index ed4fe982..11047e7e 100644 --- a/book/zh-cn/02-usability.md +++ b/book/zh-cn/02-usability.md @@ -14,9 +14,9 @@ order: 2 ### nullptr -`nullptr` 出现的目的是为了替代 `NULL`。在某种意义上来说,传统 C++ 会把 `NULL`、`0` 视为同一种东西,这取决于编译器如何定义 `NULL`,有些编译器会将 `NULL` 定义为 `((void*)0)`,有些则会直接将其定义为 `0`。 +`nullptr` 出现的目的是为了替代 `NULL`。 C 与 C++ 语言中有**空指针常量**,它们能被隐式转换成任何指针类型的空指针值,或 C++ 中的任何成员指针类型的空成员指针值。 `NULL` 由标准库实现提供,并被定义为实现定义的空指针常量。在 C 中,有些标准库会把 `NULL` 定义为 `((void*)0)` 而有些将它定义为 `0`。 -C++ **不允许**直接将 `void *` 隐式转换到其他类型。但如果编译器尝试把 `NULL` 定义为 `((void*)0)`,那么在下面这句代码中: +C++ **不允许**直接将 `void *` 隐式转换到其他类型,从而 `((void*)0)` 不是 `NULL` 的合法实现。如果标准库尝试把 `NULL` 定义为 `((void*)0)`,那么下面这句代码中会出现编译错误: ```cpp char *ch = NULL; From 54e99e14617a17c7c6f9eb7936d77e449b0e20ce Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Tue, 21 May 2024 05:54:46 +0800 Subject: [PATCH 08/14] book: avoid "let the compiler deduce the list by itself" (#277) --- book/en-us/03-runtime.md | 4 ++-- book/zh-cn/03-runtime.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/book/en-us/03-runtime.md b/book/en-us/03-runtime.md index a61d6654..8ecd2956 100644 --- a/book/en-us/03-runtime.md +++ b/book/en-us/03-runtime.md @@ -87,8 +87,8 @@ capture lists can be: - \[\] empty capture list - \[name1, name2, ...\] captures a series of variables -- \[&\] reference capture, let the compiler deduce the reference list by itself -- \[=\] value capture, let the compiler deduce the value list by itself +- \[&\] reference capture, determine the reference capture list from the uses the in function body +- \[=\] value capture, determine the value capture list from the uses in the function body #### 4. Expression capture diff --git a/book/zh-cn/03-runtime.md b/book/zh-cn/03-runtime.md index 1760b3a8..94517dc7 100644 --- a/book/zh-cn/03-runtime.md +++ b/book/zh-cn/03-runtime.md @@ -76,8 +76,8 @@ void lambda_reference_capture() { - \[\] 空捕获列表 - \[name1, name2, ...\] 捕获一系列变量 -- \[&\] 引用捕获, 让编译器自行推导引用列表 -- \[=\] 值捕获, 让编译器自行推导值捕获列表 +- \[&\] 引用捕获, 从函数体内的使用确定引用捕获列表 +- \[=\] 值捕获, 从函数体内的使用确定值捕获列表 #### 4. 表达式捕获 From 5c50dbc591b045e3633fbe957c7702e483664566 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Tue, 21 May 2024 05:56:11 +0800 Subject: [PATCH 09/14] book: avoid implication that `volatile` may be usable in concurrency (#281) --- book/en-us/07-thread.md | 2 +- book/zh-cn/07-thread.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/book/en-us/07-thread.md b/book/en-us/07-thread.md index 379d4d2a..14f74062 100644 --- a/book/en-us/07-thread.md +++ b/book/en-us/07-thread.md @@ -228,7 +228,7 @@ We simply can't expect multiple consumers to be able to produce content in a par ## 7.5 Atomic Operation and Memory Model Careful readers may be tempted by the fact that the example of the producer-consumer model in the previous section may have compiler optimizations that cause program errors. -For example, the boolean `notified` is not modified by `volatile`, and the compiler may have optimizations for this variable, such as the value of a register. +For example, the compiler may have optimizations for the variable `notified`, such as the value of a register. As a result, the consumer thread can never observe the change of this value. This is a good question. To explain this problem, we need to further discuss the concept of the memory model introduced from C++11. Let's first look at a question. What is the output of the following code? ```cpp diff --git a/book/zh-cn/07-thread.md b/book/zh-cn/07-thread.md index 8e11407d..c32a3c6b 100644 --- a/book/zh-cn/07-thread.md +++ b/book/zh-cn/07-thread.md @@ -232,7 +232,7 @@ int main() { ## 7.5 原子操作与内存模型 细心的读者可能会对前一小节中生产者消费者模型的例子可能存在编译器优化导致程序出错的情况产生疑惑。 -例如,布尔值 `notified` 没有被 `volatile` 修饰,编译器可能对此变量存在优化,例如将其作为一个寄存器的值, +例如,编译器可能对变量 `notified` 存在优化,例如将其作为一个寄存器的值, 从而导致消费者线程永远无法观察到此值的变化。这是一个好问题,为了解释清楚这个问题,我们需要进一步讨论 从 C++ 11 起引入的内存模型这一概念。我们首先来看一个问题,下面这段代码输出结果是多少? @@ -242,7 +242,7 @@ int main() { int main() { int a = 0; - int flag = 0; + volatile int flag = 0; std::thread t1([&]() { while (flag != 1); From 78b1cdf6bb454a7ed067fc2e81faa719a847935d Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Tue, 21 May 2024 05:58:17 +0800 Subject: [PATCH 10/14] book: correct description of function template deduction from `auto` (#280) --- book/en-us/02-usability.md | 16 +++++++++++----- book/zh-cn/02-usability.md | 17 +++++++++++------ 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/book/en-us/02-usability.md b/book/en-us/02-usability.md index 51d3edcf..eb8a21aa 100644 --- a/book/en-us/02-usability.md +++ b/book/en-us/02-usability.md @@ -418,17 +418,23 @@ auto i = 5; // i as int auto arr = new auto(10); // arr as int * ``` -Since C++ 20, `auto` can even be used as function arguments. Consider -the following example: +Since C++ 14, `auto` can even be used as function arguments in generic lambda expressions, +and such functionality is generalized to normal functions in C++ 20. +Consider the following example: ```cpp -int add(auto x, auto y) { +auto add14 = [](auto x, auto y) -> int { + return x+y; +} + +int add20(auto x, auto y) { return x+y; } auto i = 5; // type int auto j = 6; // type int -std::cout << add(i, j) << std::endl; +std::cout << add14(i, j) << std::endl; +std::cout << add20(i, j) << std::endl; ``` > **Note**: `auto` cannot be used to derive array types yet: @@ -481,7 +487,7 @@ type z == type x ### tail type inference -You may think that when we introduce `auto`, we have already mentioned that `auto` cannot be used for function arguments for type derivation. Can `auto` be used to derive the return type of a function? Still consider an example of an add function, which we have to write in traditional C++: +You may think that whether `auto` can be used to deduce the return type of a function. Still consider an example of an add function, which we have to write in traditional C++: ```cpp template diff --git a/book/zh-cn/02-usability.md b/book/zh-cn/02-usability.md index 11047e7e..c39f60a7 100644 --- a/book/zh-cn/02-usability.md +++ b/book/zh-cn/02-usability.md @@ -354,17 +354,22 @@ auto i = 5; // i 被推导为 int auto arr = new auto(10); // arr 被推导为 int * ``` -从 C++ 20 起,`auto` 甚至能用于函数传参,考虑下面的例子: +从 C++ 14 起,`auto` 能用于 lambda 表达式中的函数传参,而 C++ 20 起该功能推广到了一般的函数。考虑下面的例子: ```cpp -int add(auto x, auto y) { +auto add14 = [](auto x, auto y) -> int { return x+y; } -auto i = 5; // 被推导为 int -auto j = 6; // 被推导为 int -std::cout << add(i, j) << std::endl; +int add20(auto x, auto y) { + return x+y; +} + +auto i = 5; // type int +auto j = 6; // type int +std::cout << add14(i, j) << std::endl; +std::cout << add20(i, j) << std::endl; ``` > @@ -413,7 +418,7 @@ type z == type x ### 尾返回类型推导 -你可能会思考,在介绍 `auto` 时,我们已经提过 `auto` 不能用于函数形参进行类型推导,那么 `auto` 能不能用于推导函数的返回类型呢?还是考虑一个加法函数的例子,在传统 C++ 中我们必须这么写: +你可能会思考, `auto` 能不能用于推导函数的返回类型呢?还是考虑一个加法函数的例子,在传统 C++ 中我们必须这么写: ```cpp template From af45678ad42ddad195c954a5dd7ad80398440175 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?mq=E7=99=BD?= <3326284481@qq.com> Date: Tue, 21 May 2024 13:14:12 +0800 Subject: [PATCH 11/14] book: revise wording about "stack unwinding" --- book/en-us/07-thread.md | 4 +++- book/zh-cn/07-thread.md | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/book/en-us/07-thread.md b/book/en-us/07-thread.md index 14f74062..8173aefd 100644 --- a/book/en-us/07-thread.md +++ b/book/en-us/07-thread.md @@ -67,7 +67,9 @@ int main() { ``` Because C++ guarantees that all stack objects will be destroyed at the end of the declaration period, such code is also extremely safe. -Whether `critical_section()` returns normally or if an exception is thrown in the middle, a stack rollback is thrown, and `unlock()` is automatically called. +Whether `critical_section()` returns normally or if an exception is thrown in the middle, a stack unwinding is thrown, and `unlock()` is automatically called. + +> An exception is thrown and not caught (it is implementation-defined whether any stack unwinding is done in this case). `std::unique_lock` is more flexible than `std::lock_guard`. Objects of `std::unique_lock` manage the locking and unlocking operations on the `mutex` object with exclusive ownership (no other `unique_lock` objects owning the ownership of a `mutex` object). So in concurrent programming, it is recommended to use `std::unique_lock`. diff --git a/book/zh-cn/07-thread.md b/book/zh-cn/07-thread.md index c32a3c6b..ba80e7e5 100644 --- a/book/zh-cn/07-thread.md +++ b/book/zh-cn/07-thread.md @@ -68,7 +68,9 @@ int main() { ``` 由于 C++ 保证了所有栈对象在生命周期结束时会被销毁,所以这样的代码也是异常安全的。 -无论 `critical_section()` 正常返回、还是在中途抛出异常,都会引发堆栈回退,也就自动调用了 `unlock()`。 +无论 `critical_section()` 正常返回、还是在中途抛出异常,都会引发栈回溯,也就自动调用了 `unlock()`。 + +> 没有捕获抛出的异常(此时由实现定义是否进行栈回溯)。 而 `std::unique_lock` 则是相对于 `std::lock_guard` 出现的,`std::unique_lock` 更加灵活, `std::unique_lock` 的对象会以独占所有权(没有其他的 `unique_lock` 对象同时拥有某个 `mutex` 对象的所有权) From 2659a5f2073d7a96224567a9ebd0d5e5c266f6ba Mon Sep 17 00:00:00 2001 From: Shaobo Liu Date: Sat, 1 Jun 2024 18:08:51 +0800 Subject: [PATCH 12/14] book: add missing result (#291) Co-authored-by: Shaobo Liu --- book/zh-cn/02-usability.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/zh-cn/02-usability.md b/book/zh-cn/02-usability.md index c39f60a7..e9c84e9a 100644 --- a/book/zh-cn/02-usability.md +++ b/book/zh-cn/02-usability.md @@ -963,7 +963,7 @@ enum class new_enum : unsigned int { ```cpp if (new_enum::value3 == new_enum::value4) { - // 会输出 + // 会输出true std::cout << "new_enum::value3 == new_enum::value4" << std::endl; } ``` From 7b57e5e5a10a5707d278ffd4172815821202a6c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?mq=E7=99=BD?= <3326284481@qq.com> Date: Sat, 1 Jun 2024 18:09:32 +0800 Subject: [PATCH 13/14] book: revise the description of RAII (#288) --- book/en-us/07-thread.md | 2 +- book/zh-cn/07-thread.md | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/book/en-us/07-thread.md b/book/en-us/07-thread.md index 8173aefd..2279efdc 100644 --- a/book/en-us/07-thread.md +++ b/book/en-us/07-thread.md @@ -35,7 +35,7 @@ C++11 introduces a class related to `mutex`, with all related functions in the ` It can be locked by its member function `lock()`, and `unlock()` can be unlocked. But in the process of actually writing the code, it is best not to directly call the member function, Because calling member functions, you need to call `unlock()` at the exit of each critical section, and of course, exceptions. -At this time, C++11 also provides a template class `std::lock_guard` for the RAII syntax for the mutex. +At this time, C++11 also provides a template class `std::lock_guard` for the RAII mechanism for the mutex. RAII guarantees the exceptional security of the code while keeping the simplicity of the code. diff --git a/book/zh-cn/07-thread.md b/book/zh-cn/07-thread.md index ba80e7e5..dbb35085 100644 --- a/book/zh-cn/07-thread.md +++ b/book/zh-cn/07-thread.md @@ -35,7 +35,8 @@ C++11 引入了 `mutex` 相关的类,其所有相关的函数都放在 ` Date: Sat, 1 Jun 2024 18:10:55 +0800 Subject: [PATCH 14/14] book: revise usage of "mutex" and "instantiation" (#292) --- book/en-us/07-thread.md | 8 ++++---- book/zh-cn/07-thread.md | 7 +++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/book/en-us/07-thread.md b/book/en-us/07-thread.md index 2279efdc..a9f41162 100644 --- a/book/en-us/07-thread.md +++ b/book/en-us/07-thread.md @@ -31,7 +31,7 @@ int main() { We have already learned the basics of concurrency technology in the operating system, or the database, and `mutex` is one of the cores. C++11 introduces a class related to `mutex`, with all related functions in the `` header file. -`std::mutex` is the most basic `mutex` class in C++11, and you can create a mutex by instantiating `std::mutex`. +`std::mutex` is the most basic mutex class in C++11, and a mutex can be created by constructing a `std::mutex` object. It can be locked by its member function `lock()`, and `unlock()` can be unlocked. But in the process of actually writing the code, it is best not to directly call the member function, Because calling member functions, you need to call `unlock()` at the exit of each critical section, and of course, exceptions. @@ -160,7 +160,7 @@ After encapsulating the target to be called, you can use `get_future()` to get a The condition variable `std::condition_variable` was born to solve the deadlock and was introduced when the mutex operation was not enough. For example, a thread may need to wait for a condition to be true to continue execution. A dead wait loop can cause all other threads to fail to enter the critical section so that when the condition is true, a deadlock occurs. -Therefore, the `condition_variable` instance is created primarily to wake up the waiting thread and avoid deadlocks. +Therefore, the `condition_variable` object is created primarily to wake up the waiting thread and avoid deadlocks. `notify_one()` of `std::condition_variable` is used to wake up a thread; `notify_all()` is to notify all threads. Below is an example of a producer and consumer model: @@ -276,8 +276,8 @@ This is a very strong set of synchronization conditions, in other words when it This seems too harsh for a variable that requires only atomic operations (no intermediate state). The research on synchronization conditions has a very long history, and we will not go into details here. Readers should understand that under the modern CPU architecture, atomic operations at the CPU instruction level are provided. -Therefore, in the C++11 multi-threaded shared variable reading and writing, the introduction of the `std::atomic` template, so that we instantiate an atomic type, will be an -Atomic type read and write operations are minimized from a set of instructions to a single CPU instruction. E.g: +Therefore, the `std::atomic` template is introduced in C++11 for the topic of multi-threaded shared variable reading and writing, which enables us to instantiate atomic types, +and minimize an atomic read or write operation from a set of instructions to a single CPU instruction. E.g: ```cpp std::atomic counter; diff --git a/book/zh-cn/07-thread.md b/book/zh-cn/07-thread.md index dbb35085..3c59a72d 100644 --- a/book/zh-cn/07-thread.md +++ b/book/zh-cn/07-thread.md @@ -31,7 +31,7 @@ int main() { 我们在操作系统、亦或是数据库的相关知识中已经了解过了有关并发技术的基本知识,`mutex` 就是其中的核心之一。 C++11 引入了 `mutex` 相关的类,其所有相关的函数都放在 `` 头文件中。 -`std::mutex` 是 C++11 中最基本的 `mutex` 类,通过实例化 `std::mutex` 可以创建互斥量, +`std::mutex` 是 C++11 中最基本的互斥量类,可以通过构造 `std::mutex` 对象创建互斥量, 而通过其成员函数 `lock()` 可以进行上锁,`unlock()` 可以进行解锁。 但是在实际编写代码的过程中,最好不去直接调用成员函数, 因为调用成员函数就需要在每个临界区的出口处调用 `unlock()`,当然,还包括异常。 @@ -163,7 +163,7 @@ int main() { 条件变量 `std::condition_variable` 是为了解决死锁而生,当互斥操作不够用而引入的。 比如,线程可能需要等待某个条件为真才能继续执行, 而一个忙等待循环中可能会导致所有其他线程都无法进入临界区使得条件为真时,就会发生死锁。 -所以,`condition_variable` 实例被创建出现主要就是用于唤醒等待线程从而避免死锁。 +所以,`condition_variable` 对象被创建出现主要就是用于唤醒等待线程从而避免死锁。 `std::condition_variable`的 `notify_one()` 用于唤醒一个线程; `notify_all()` 则是通知所有线程。下面是一个生产者和消费者模型的例子: @@ -283,8 +283,7 @@ int main() { 这对于一个仅需原子级操作(没有中间态)的变量,似乎太苛刻了。 关于同步条件的研究有着非常久远的历史,我们在这里不进行赘述。读者应该明白,现代 CPU 体系结构提供了 CPU 指令级的原子操作, -因此在 C++11 中多线程下共享变量的读写这一问题上,还引入了 `std::atomic` 模板,使得我们实例化一个原子类型,将一个 -原子类型读写操作从一组指令,最小化到单个 CPU 指令。例如: +因此在多线程下共享变量的读写这一问题上, C++11 中还引入了 `std::atomic` 模板,使得我们能实例化原子类型,并将一个原子写操作从一组指令,最小化到单个 CPU 指令。例如: ```cpp std::atomic counter;