From f65547e3a5f264794cfc89faf436e60343f4eb4a Mon Sep 17 00:00:00 2001 From: David Date: Thu, 28 Jan 2021 00:31:57 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E7=BF=BB=E8=AF=91=E9=94=99?= =?UTF-8?q?=E8=AF=AF=20(#73)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix typo; add xmind * 修正翻译错误 Co-authored-by: wendajiang --- 7.TheConcurrencyAPI/item37.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/7.TheConcurrencyAPI/item37.md b/7.TheConcurrencyAPI/item37.md index 0a15a08..52dc52c 100644 --- a/7.TheConcurrencyAPI/item37.md +++ b/7.TheConcurrencyAPI/item37.md @@ -53,7 +53,7 @@ constexpr auto tenMillion = 10'000'000; // C++14 你可能会想,为什么`std::thread`析构的行为是这样的,那是因为另外两种显而易见的方式更糟: -- **隐式join**。这种情况下,`std::thread`的析构函数将等待其底层的异步执行线程完成。这听起来是合理的,但是可能会导致性能异常,而且难以追踪。比如,如果`conditonAreStatisfied()`已经返回了假,`doWork`继续等待过滤器应用于所有值就很违反直觉。 +- **隐式join**。这种情况下,`std::thread`的析构函数将等待其底层的异步执行线程完成。这听起来是合理的,但是可能会导致表现异常,而且难以追踪。比如,如果`conditonAreStatisfied()`已经返回了假,`doWork`继续等待过滤器应用于所有值就很违反直觉。 - **隐式detach**。这种情况下,`std::thread`析构函数会分离其底层的线程。线程继续运行。听起来比join的方式好,但是可能导致更严重的调试问题。比如,在`doWork`中,`goodVals`是通过引用捕获的局部变量。可能会被lambda修改。假定,lambda的执行时异步的,`conditionsAreStatisfied()`返回假。这时,`doWork`返回,同时局部变量`goodVals`被销毁。堆栈被弹出,并在`doWork`的调用点继续执行线程 @@ -137,9 +137,9 @@ bool doWork(std::function filter, int maxVal = tenMillion) } ``` -这份代码中,我们选择在`ThreadRAII`的析构函数中异步执行`join`的动作,因为我们先前分析中,`detach`可能导致非常难缠的bug。我们之前也分析了`join`可能会导致性能异常(坦率说,也可能调试困难),但是在未定义行为(`detach`导致),程序终止(`std::thread`默认导致),或者性能异常之间选择一个后果,可能性能异常是最好的那个。 +这份代码中,我们通过`ThreadRAII`的析构函数对异步执行的线程进行`join`,因为在先前分析中,`detach`可能导致非常难缠的bug。我们之前也分析了`join`可能会导致表现异常(坦率说,也可能调试困难),但是在未定义行为(`detach`导致),程序终止(`std::thread`默认导致),或者表现异常之间选择一个后果,可能表现异常是最好的那个。 -哎,Item 39表明了使用`ThreadRAII`来保证在`std::thread`的析构时执行`join`有时可能不仅导致程序性能异常,还可能导致程序挂起。“适当”的解决方案是此类程序应该和异步执行的lambda通信,告诉它不需要执行了,可以直接返回,但是C++11中不支持可中断线程。可以自行实现,但是这不是本书讨论的主题。(译者注:关于这一点,C++ Concurrency in Action 的section 9.2 中有详细讨论,也有中文版出版) +哎,Item 39表明了使用`ThreadRAII`来保证在`std::thread`的析构时执行`join`有时可能不仅导致程序表现异常,还可能导致程序挂起。“适当”的解决方案是此类程序应该和异步执行的lambda通信,告诉它不需要执行了,可以直接返回,但是C++11中不支持可中断线程。可以自行实现,但是这不是本书讨论的主题。(译者注:关于这一点,C++ Concurrency in Action 的section 9.2 中有详细讨论,也有中文版出版) Item 17说明因为`ThreadRAII`声明了一个析构函数,因此不会有编译器生成移动操作,但是没有理由`ThreadRAII`对象不能移动。所以需要我们显式声明来告诉编译器自动生成: @@ -171,6 +171,6 @@ private: ### 需要记住的事 - 在所有路径上保证`thread`最终是unjoinable -- 析构时`join`会导致难以调试的性能异常问题 +- 析构时`join`会导致难以调试的表现异常问题 - 析构时`detach`会导致难以调试的未定义行为 - 声明类数据成员时,最后声明`std::thread`类型成员 \ No newline at end of file