まとめ
私が初めて「マルチスレッド」によるプログラミングを行ったのは、1999年です。それ以前は、「マルチタスク」によるプログラミングを行っていました。その、初めてのマルチスレッドプログラミングを行った後、部ではじめてマルチスレッドプログラミングを扱った事例であったため、レポートを提出しています。そのレポートから編集して引用し、まとめとします。
1)スレッドセーフとスレッドクリティカル
新たに製造する関数をスレッドセーフにする方法は2つある。1つはその関数が共有変数領域を参照する場合に実行中のスレッドが必ず1つになるようにロックしてしまう方法、もう1つは他のスレッドから独立した領域を参照するようにする方法である。しかし、前者の方法を使うと、これからロックを行おうとしている他のスレッドは、ロックが解放されるまで待たなければならない。これではせっかく複数の処理が同時に実行されるマルチスレッドを用いている意味が無くなってしまう。また、後者のようにすべての変数をスレッドごとに独立させるとメモリ資源を浪費することになる。よって、まずスレッド間で共有しなければならないかどうかを検討する。共有しなくても良い変数であれば、スレッドごとに独立させる。ただし、大きな領域を必要とする場合は、共有することを考える。ここの見極めが、マルチスレッドプログラミングにおけるポイントの1つとなる。
2)共有変数の保護
ロックする命令とロックを解除する命令の間では同時に実行されるスレッドは1つに限定される。マルチスレッドとしてのパフォーマンスは損なわれるが、共有変数の安全性が確保される。もちろん、ロックを使用しないスレッドは、ロックによる遅延の影響を受けない。共有変数を使用しないスレッドはロックを使う必要はない。
3)ロックとパフォーマンス
ロックをしてスレッドの実行をシーケンシャルにすると、その分全体的なパフォーマンスが低下する。では、実行スピードを優先するには、ロックする範囲を小分けにした方がよいのか、それともなるべく少ないロックで大きな範囲をカバーする方がよいのか。これについては、1つのロックで多くの範囲をカバーする方がよい。しかし、その範囲に時間のかかる処理が含まれると、マルチスレッドの利点が死んでしまう。従って、少ないロックで多くの、ただし時間のかからない処理をするのがよいと言える。処理フローを見直し、時間がかかる処理はマルチスレッドの領域へ、時間がかからない処理をシーケンシャルな領域へ移動させる。必要なら、アルゴリズムの変更も検討する。
4)並行処理能力の向上
実行中、多数の処理が参照しており、限られた処理だけが更新を行う場合があるという共有変数が存在する。頻繁に書き換えられるわけではないが、参照途中に変更が行われる可能性がある以上、参照中に変更されること、変更中に参照されることは禁止しなければならない。しかし、複数のスレッドが同時に参照することは許されるべきである。オラクルなどのデータベースでは、普通に使われているロック処理である。このようなロックが用意されているなら、積極的に用いる。用意されていないなら、実装する。
参考資料
- Thread Safety in the Standard C++ Library:.NET Framework 4 の C++ における、標準ライブラリのスレッド安全性について
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 の C++ における、標準ライブラリのスレッド安全性について
For writes to the same object, , the object is thread safe for writing:
- Sun Studio 12: C++ ユーザーズ ガイド(PDF)
11.1 マルチスレッドプログラムの構築
C++ コンパイラに付属しているライブラリは、すべてマルチスレッドで使用しても安全です。
11.1.2 C++ サポートライブラリの使用
C++ サポートライブラリ(libCrun、libiostream、libCstd、libC) は、マルチスレッドで使用しても安全ですが、非同期安全(非同期例外で使用しても安全) ではありません。
- Using Concurrency
So, for 3.0, the question of "is multithreading safe for I/O" must be answered with, "is your platform's C library threadsafe for I/O?"
(As an example, the POSIX standard requires that C stdio
FILE*
operations are atomic. POSIX-conforming C libraries (e.g, on Solaris and GNU/Linux) have an internal mutex to serialize operations onFILE*
s. However, you still need to not do stupid things like callingfclose(fs)
in one thread followed by an access offs
in another.) - 『実践マルチスレッドプログラミング』(ISBN:4-7561-1784-8)