63383


こんにちは、C++の初学者です。  
ビャーネ・ストラウストラップ先生の『プログラミング言語C++
第4版』から以下のexampleを引用しました。fとF()が同じオブジェクトcoutを使っているから、出力結果が予測不能であって、「PaHerallllel
o World!」などのように崩れた出力を得るかもしれないと書かれているのですが、実際のところ、ちゃんと「Hello, Parallel
World!」と出力されます。これは何故なのでしょうか。ご教授願います。

[code]

    #include <iostream> 
    #include <thread> 
    using namespace std; 
    
    void f() { cout << "Hello, "; } 
    
    struct F { 
            void operator()() { cout << "Parallel World!\n"; } 
    }; 
    
    void user() { 
            thread t1 {f}; 
            thread t2 {F()}; 
    
            t1.join(); 
            t2.join(); 
    } 
    
    int main() { 
            user(); 
    }
    
[/code]


CC BY-SA 4.0
2020-02-26T04:33:42.920
63361
2020-02-26T23:56:48.207
37961
question
c++ c++11
threadの同期について


条件がそろわないと出力結果は混ざりません。※ だからといってクリティカルなシステムでは無視できません

  1. `cout << "Hello, ";`と`cout << "Parallel World!\n";`のスレッドがほぼ同じタイミングで実行される。  
CPUコアが複数個無いとこのような事態にはなりにくいです。※ないわけではありません。

【追記】coutがスレッドセーフかどうかネットで調べてみましたが、処理系によって異なるようです。[Is cout synchronized/thread-
safe?](https://stackoverflow.com/questions/6374264/is-cout-synchronized-
thread-safe)８年ほど前の情報ですが、出力が混ざるのは消して珍しいことではないのかも知れません。  
※ 現在多重度を増やして、出力が混ざるか実験中。

  2. `cout << "Hello, ";`と`cout << "Parallel World!\n";`が各々１回の`write`で書かれていない。  
大概の処理系では1回の`write`で実装されていると思います。

【追記】  
straceでプログラムの振る舞いを調べてみました。  
`cout << "Hello, ";`と`cout << "Parallel
World!\n";`は合わせて１回のWriteで書かれていました。coutへの書き込みはバッファリングされているようです。バッファリングの途中でスレッドのディスパッチが発生しない限り、出力が混ざることはないようです。

g++ (GCC) 8.3.1 20190507 (Red Hat 8.3.1-4)


CC BY-SA 4.0
2020-02-26T05:04:01.157
63362
2020-02-26T23:56:48.207
2020-02-26T23:56:48.207
35558
35558
63361
answer


一般的なOSの実装において、複数のプロセスやスレッドから同時に実行される可能性のある機能関数は、  
いかなる場合でも、それが期待される結果を維持するために、「再入禁止にコードされている」のが普通です。

例の場合、標準出力に期待される動作とは、「コール時に渡された全ての文字が出力される」ことだと考えられます。  
従って、当該機能はその処理(渡された文字の出力)途中では他のコール要求は受け付けず、待たされるようにコードされているのが一般的です。

特にハードウェア等、アプリ側から見て「唯一の出力先」に出力を行う場合には重要な設計です。  
例えば、ファイル出力、通信系の出力なども同様で、標準出力も歴史的経緯上、同じ扱いをされると考えられます。

つまり、一般的なOSではBjarne先生の予測通りにはならないと言えます。


CC BY-SA 4.0
2020-02-26T05:35:13.140
63364
2020-02-26T05:35:13.140
3793
63361
answer


Visual Studio 2019 で 実行したところ  
上記の `user();` 関数を １万回実行すると １３回程度

[code]

    Hello, Hello, Parallel World!
    
[/code]

や

[code]

    Parallel World!
    
[/code]

という出力結果が混じりました。

[code]

    出力結果が予測不能であって、「PaHerallllel o World!」などのように崩れた出力を得るかもしれない
    
[/code]

それは cout の内部実装が どのように スレッド間の 同期をとっているかわからないので  
予測不可能だと思います。  
１文字づつ 同期しているなら 例のように混在するかもしれません。

`cout` へのアクセスは スレッドセーフですが  
その出力する文字は混じるかもしれませんと  
[MSDN でも 書かれていました。](https://docs.microsoft.com/ja-jp/cpp/standard-
library/thread-safety-in-the-cpp-standard-library?view=vs-2019)


CC BY-SA 4.0
2020-02-26T14:17:37.447
63383
2020-02-26T14:17:37.447
18851
63361
answer