ネタ元から引用。
スレッドセーフとインテルTBBのコンテナの、コメントより:
最後にcoutの取り扱いについての注意するべき点を書きます。このサンプルでは単純化するためにロック処理をしていませんが、coutはスレッドセーフではないので、並列処理時にcoutに出力を指定するとコンソール画面の表示が滅茶苦茶になります。試しにparallel_for( blocked_range( 0, count, 10000 ), pop );の部分をparallel_for( blocked_range( 0, count, 1 ), pop );に変えてみてください。何度も実行すると表示がおかしくなるのが確認できます。もしうまく行かない場合は、さらにcout << value << " ";の部分を変更して、長い文字列を出力するようにしてください。
これを踏まえて、コメント。
インドリ (2010/03/03 09:12)
>スケジューラーの初期化について
並列処理では実行順序が保障されません。
しかも、アセンブラレベルで命令が実行されております。
その状態なのですから、初心者がTBBとネイティブスレッド・OpenMPなどの処理を併用させたときに、
どのようなプログラムでも正しく実行できると100%の自信を持って言えるでしょうか?
私はそんな危険を冒すよりも1行のプログラムを書く方を勧めます。
インドリ (2010/03/03 15:55)
スレッドセーフをもっと正式に言いますと、クラスが複数のスレッドからアクセスされた時に、各スレッドのスケジューリングや実行のタイミングがどうであっても、また呼び出し側コードからの同期化努力やその他の調停努力がなくても正しく振舞う事をスレッドセーフといいます。
MSの実装ではcoutを一行で書いた場合、短いサンプルでは一応各文字が混ざる事はありません。
しかし、必ず一行で書くというのは実務的に考えて無理な話です。
ですから普通の人は・・・
cout << "foo" << .....
(なんらかの処理をする)
cout << "bar" << ...
とプログラミングするでしょう。
また必ず一行で書くという行為はcoutという標準出力オブジェクトの不変項と事後条件を満たしていると言えるでしょうか?
ふぅ。。。なんという素人。
まず、cout、iostream がスレッドセーフであるというエビデンスから。
Sun Studio 12 Update 1: C++ ユーザーズガイドより:
11.1 マルチスレッドプログラムの構築
C++ コンパイラに付属しているライブラリは、すべてマルチスレッドで使用しても安全です。
11.1.2 C++ サポートライブラリの使用
C++ サポートライブラリ(llibCrun、libiostream、libCstd、libC) は、マルチスレッドで使用しても安全ですが、非同期では安全(非同期例外で使用しても安全) ではありません。したがって、マルチスレッドアプリケーションのシグナルハンドラでは、これらのライブラリに含まれている関数を使用しないでください。使用するとデッドロックが発生する可能性があります。マルチスレッドアプリケーションのシグナルハンドラでは、次のものは安全に使用できません。
- iostream
- new 式とdelete 式
- 例外
11.3 C++ 標準ライブラリのオブジェクトのスレッド間での共有
C++ 標準ライブラリ(libCstd -library=Cstd) は、いくつかのロケールを除けばマルチスレッドで使用しても安全なライブラリで、このライブラリの内部は、マルチスレッド環境で正しく機能することが保証されています。ただし、依然、スレッド間で共有するライブラリオブジェクト周りには注意を払う必要があります。setlocale(3C) およびattributes(5) のマニュアルページを参照してください。
Thread Safety in the Standard C++ Library (.NET Framework 4)より:
iostream Classes
The iostream classes follow the same rules as the other classes, with one exception. It is safe to write to an object from multiple threads. For example, thread 1 can write to cout at the same time as thread 2. However, this can result in the output from the two threads being intermixed.
Thread Safety in the Standard C++ Library (.NET Framework 1.1)より:
iostream Classes
Note that reading from a stream buffer is not considered to be a read operation. It should be considered as a write operation, because this changes the state of the class.
For reads to the same object, the object is thread safe for reading:
- From one thread at a time when no writers on other threads.
- From many threads at a time when no writers on other threads.
For writes to the same object, , the object is thread safe for writing:
- From one thread when no readers on other threads.
- From many threads (when accesses are limited to stream buffers).
For reads to different objects of the same class, , the object is thread safe for reading:
- From one thread at a time.
- From one thread at a time when no writers on other threads.
- From many threads at a time.
- From many threads at a time when no writers on other threads.
For writes to different objects of the same class, the object is thread safe for writing:
- From one thread when no readers on other threads
- From many threads
この様に、iostream は、スレッド セーフです。ただし、スレッド セーフなライブラリだけを使ったからといって、アプリケーションがスレッド セーフになるわけではありません。ここの所を勘違いすると、困ったことになります。上の例は、そういう勘違いをしているわけです。
さて、どういうことでしょうか。
concurrent_queue は、マルチ スレッドで使えるように、TBB で用意されたクラスです。このクラスに用意されたメソッドは、スレッド セーフです。では、次のようなプログラムを作ったら、どうなるでしょう?
キューは、concurrent_bounded_queue を使うものとする。
スレッド1() {
1~10000のうち、奇数をキュー インする。
}
スレッド2() {
1~10000のうち、偶数をキュー インする。
}
こんなことでコード書いて動作検証するのも面倒。はい、上記2つを、並列に動作するスレッドで呼び出したとします。キューには、どの様に入るでしょうか。答え。予測不能。はい、アプリケーションは、マルチ スレッドで、期待する動作と異なる結果を返しました。よって、「concurrent_bounded_queue はスレッド アンセーフです」。
そんなバカな。
スレッド アンセーフなのはアプリケーションであって、concurrent_bounded_queue ではありません。もしくは、「スレッド セーフか」は関数やメソッド単位で保証されるものであり、開発者がアプリケーションとしてどうなのかを作り込みます。ここを取り違えて「cout はスレッド セーフではない
」というのは、まったく馬鹿げています。いじょ。
投稿日時 : 2010年3月12日 0:26