@@ -421,7 +421,7 @@ <h2 id="index-_1">前言</h2>
421
421
<blockquote>
422
422
<p><img src="../img/bulb.png" height="30px" width="auto" style="margin: 0; border: none"/> 本书还在持续更新中……要追番的话,可以在 <a href="https://github.com/parallel101/cppguidebook">GitHub</a> 点一下右上角的 “Watch” 按钮,每当小彭老师提交新 commit,GitHub 会向你发送一封电子邮件,提醒你小彭老师更新了。</p>
423
423
</blockquote>
424
- <p>更新时间:2024年10月18日 15:46:43 (UTC+08:00)</p>
424
+ <p>更新时间:2024年10月18日 15:48:05 (UTC+08:00)</p>
425
425
<p><a href="https://parallel101.github.io/cppguidebook">在 GitHub Pages 浏览本书</a> | <a href="https://142857.red/book">在小彭老师自己维护的镜像上浏览本书</a></p>
426
426
<h2 id="index-_2">格式约定</h2>
427
427
<blockquote>
@@ -1880,6 +1880,7 @@ <h2 id="cpp_tricks-cout">多线程中 cout 出现乱序?</h2>
1880
1880
</blockquote>
1881
1881
<p>他们中间可能穿插了其他线程的 cout,从而导致你 <code>"the answer is"</code> 打印完后,被其他线程的 <code>'\n'</code> 插入进来,导致换行混乱。</p>
1882
1882
<blockquote>
1883
+ <p><img src="../img/warning.png" height="30px" width="auto" style="margin: 0; border: none"/> <code>std::cout</code> 的 <code>operator<<</code> 调用是线程安全的,不会被打断,但多个 <code>operator<<</code> 的调用在多线程环境中可能会 <strong>交错</strong> ,导致输出结果混乱。</p>
1883
1884
<p><img src="../img/bulb.png" height="30px" width="auto" style="margin: 0; border: none"/> 更多细节请看我们的 <a href="#threading">多线程专题</a>。</p>
1884
1885
</blockquote>
1885
1886
<p>解决方法是,先创建一个只属于当前线程的 <code>ostringstream</code>,最后一次性调用一次 cout 的 <code>operator<<</code>,让“原子”的单位变成“一行”而不是一个字符串。</p>
@@ -1890,8 +1891,12 @@ <h2 id="cpp_tricks-cout">多线程中 cout 出现乱序?</h2>
1890
1891
<p>或者,使用 <code>std::format</code>:</p>
1891
1892
<pre><code class="language-cpp">cout << std::format("the answer is {}\n", 42);
1892
1893
</code></pre>
1893
- <p>总之,就是要让 <code>operator<<</code> 只有一次。</p>
1894
- <p>建议各位升级到 C++23,然后改用 <code>std::println</code> 吧:</p>
1894
+ <p>总之,就是要让 <code>operator<<</code> 只有一次,自然就是没有交错。</p>
1895
+ <p>在 C++20 中,可以改用 <code>std::osyncstream(std::cout)</code> 代替 <code>std::cout</code> :</p>
1896
+ <pre><code class="language-cpp">std::osyncstream(std::cout) << "the answer is " << 42 << '\n';
1897
+ </code></pre>
1898
+ <p><code>std::osyncstream</code> 可以保证:1. 不会产生数据竞争;2. 不会发生穿插和截断。可以理解为 <code>std::osyncstream</code> 在构造时对缓冲区上锁,在析构时解锁。</p>
1899
+ <p>如果你的标准库支持 C++23,还可以用 <code>std::println</code>,这个函数的输出也是原子的(第三方库如 <code>fmt::println</code> 亦可):</p>
1895
1900
<pre><code class="language-cpp">std::println("the answer is {}", 42);
1896
1901
</code></pre>
1897
1902
<h2 id="cpp_tricks-cerr-cout">cerr 与 cout 的抉择</h2>
0 commit comments