From 66b6edb6a43c4ec8601919bb176b5f78a5ddf074 Mon Sep 17 00:00:00 2001 From: mq-b <3326284481@qq.com> Date: Wed, 9 Oct 2024 14:17:22 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E8=A1=A5=E5=85=85=20`std::cout`=20?= =?UTF-8?q?=E5=A4=9A=E7=BA=BF=E7=A8=8B=E8=BE=93=E5=87=BA=E4=BA=A4=E9=94=99?= =?UTF-8?q?=E7=9A=84=E8=AF=B4=E6=98=8E=E4=B8=8E=E6=94=B9=E8=BF=9B=E6=96=B9?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/cpp_tricks.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/docs/cpp_tricks.md b/docs/cpp_tricks.md index b5b5c20..5d2fd9d 100644 --- a/docs/cpp_tricks.md +++ b/docs/cpp_tricks.md @@ -1,6 +1,6 @@ # 应知应会 C++ 小技巧 -[TOC] +[toc] ## 交换两个变量 @@ -1029,6 +1029,8 @@ cout << '\n'; > {{ icon.fun }} 而是分子了 :) +`std::cout` 的 `operator<<` 调用是线程安全的,不会被打断,但多个 `operator<<` 的调用在多线程环境中可能会 **交错** ,导致输出结果混乱 + 他们中间可能穿插了其他线程的 cout,从而导致你 `"the answer is"` 打印完后,被其他线程的 `'\n'` 插入进来,导致换行混乱。 > {{ icon.tip }} 更多细节请看我们的 [多线程专题](threading.md)。 @@ -1047,9 +1049,17 @@ cout << oss.str(); cout << std::format("the answer is {}\n", 42); ``` -总之,就是要让 `operator<<` 只有一次。 +总之,就是要让 `operator<<` 只有一次,自然就是没有交错。 + +如果可以使用 C++20,就可改用 `std::osyncstream{ std::cout }` : + +```cpp +std::osyncstream{ std::cout } << "the answer is " << 42 << '\n'; +``` + +`std::osyncstream` 提供保证:所有对最终目标缓冲区(上例中是 [std::cout](https://zh.cppreference.com/w/cpp/io/cout "cpp/io/cout"))作出的输出将免除数据竞争,而且将不以任何方式穿插或截断。 -建议各位升级到 C++23,然后改用 `std::println` 吧: +如果可以使用 C++23,就可改用 `std::println` : ```cpp std::println("the answer is {}", 42); From bfefda9df97a658038566553eaa1b236197efdb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BD=AD=E4=BA=8E=E6=96=8C?= <1931127624@qq.com> Date: Wed, 9 Oct 2024 16:01:00 +0800 Subject: [PATCH 2/3] Apply suggestions from code review --- docs/cpp_tricks.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/cpp_tricks.md b/docs/cpp_tricks.md index 5d2fd9d..ae55db6 100644 --- a/docs/cpp_tricks.md +++ b/docs/cpp_tricks.md @@ -1,6 +1,6 @@ # 应知应会 C++ 小技巧 -[toc] +[TOC] ## 交换两个变量 @@ -1029,10 +1029,10 @@ cout << '\n'; > {{ icon.fun }} 而是分子了 :) -`std::cout` 的 `operator<<` 调用是线程安全的,不会被打断,但多个 `operator<<` 的调用在多线程环境中可能会 **交错** ,导致输出结果混乱 - 他们中间可能穿插了其他线程的 cout,从而导致你 `"the answer is"` 打印完后,被其他线程的 `'\n'` 插入进来,导致换行混乱。 +> {{ icon.warn }} `std::cout` 的 `operator<<` 调用是线程安全的,不会被打断,但多个 `operator<<` 的调用在多线程环境中可能会 **交错** ,导致输出结果混乱。 + > {{ icon.tip }} 更多细节请看我们的 [多线程专题](threading.md)。 解决方法是,先创建一个只属于当前线程的 `ostringstream`,最后一次性调用一次 cout 的 `operator<<`,让“原子”的单位变成“一行”而不是一个字符串。 @@ -1051,15 +1051,15 @@ cout << std::format("the answer is {}\n", 42); 总之,就是要让 `operator<<` 只有一次,自然就是没有交错。 -如果可以使用 C++20,就可改用 `std::osyncstream{ std::cout }` : +在 C++20 中,可以改用 `std::osyncstream(std::cout)` 代替 `std::cout` : ```cpp -std::osyncstream{ std::cout } << "the answer is " << 42 << '\n'; +std::osyncstream(std::cout) << "the answer is " << 42 << '\n'; ``` -`std::osyncstream` 提供保证:所有对最终目标缓冲区(上例中是 [std::cout](https://zh.cppreference.com/w/cpp/io/cout "cpp/io/cout"))作出的输出将免除数据竞争,而且将不以任何方式穿插或截断。 +`std::osyncstream` 可以保证:1. 不会产生数据竞争;2. 不会发生穿插和截断。可以理解为 `std::osyncstream` 在构造时对缓冲区上锁,在析构时解锁。 -如果可以使用 C++23,就可改用 `std::println` : +如果你的标准库支持 C++23,还可以用 `std::println`,这一整个打印操作也是原子的(第三方库如 `fmt::println` 亦可): ```cpp std::println("the answer is {}", 42); From a7f3be3877e56810e99f224531c17ed14130f79f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BD=AD=E4=BA=8E=E6=96=8C?= <1931127624@qq.com> Date: Wed, 9 Oct 2024 16:02:46 +0800 Subject: [PATCH 3/3] Apply suggestions from code review --- docs/cpp_tricks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/cpp_tricks.md b/docs/cpp_tricks.md index ae55db6..29cd0ea 100644 --- a/docs/cpp_tricks.md +++ b/docs/cpp_tricks.md @@ -1059,7 +1059,7 @@ std::osyncstream(std::cout) << "the answer is " << 42 << '\n'; `std::osyncstream` 可以保证:1. 不会产生数据竞争;2. 不会发生穿插和截断。可以理解为 `std::osyncstream` 在构造时对缓冲区上锁,在析构时解锁。 -如果你的标准库支持 C++23,还可以用 `std::println`,这一整个打印操作也是原子的(第三方库如 `fmt::println` 亦可): +如果你的标准库支持 C++23,还可以用 `std::println`,这个函数的输出也是原子的(第三方库如 `fmt::println` 亦可): ```cpp std::println("the answer is {}", 42);