スレッドセーフ
出典: フリー百科事典『ウィキペディア(Wikipedia)』
スレッドセーフ(Thread-safe)は、マルチスレッドプログラミングにおける概念である。あるコードがスレッドセーフであるという場合、そのコードを複数のスレッドが同時並行的に実行しても問題が発生しないことを意味する。特に、ある共有データへの複数のスレッドによるアクセスがあるとき、一度に1つのスレッドのみがその共有データにアクセスするようにして安全性を確保しなければならない。
スレッドセーフはマルチスレッドプログラミングにおける重要な要素である。それは従来、オペレーティングシステムの開発者だけが考慮しなければならない問題だったが、1990年代後半には一般的な問題となった。マルチスレッドプログラムでは、複数のスレッドが同じアドレス空間内で同時に実行される。各スレッドのアクセスするメモリ領域が特に制限されることはなく、全スレッドが全アドレス空間にアクセスできる。従って、プログラムを見たときに予測される制御の流れやデータアクセスの順序は実際に実行時に起きることとかけ離れたものとなることが多い。これは「驚き最小の原則」に反している。スレッドセーフは実際の処理の流れとプログラムのソースコードの関連性を強化し、予期しない動作を最小にすることを指向した特性である。
目次 |
[編集] スレッドセーフかどうかの判断基準
あるコードの断片がスレッドセーフかどうかを判断するのは簡単ではない。しかし、以下のような点に注意して調べることで問題が見つかることが多い。
- 広域変数やヒープにアクセスしているかどうか
- グローバルな制限のあるリソース(ファイル、プロセスなど)を確保・解放しているかどうか
- 参照やポインタによる間接アクセスをしているかどうか
- 明確な副作用があるかどうか(例えば、C言語で volatile 変数にアクセスするなど)
リエントラントなサブルーチンはスレッドセーフである。スタック上の変数のみを使用し、引数にのみ依存し、同様な特性のサブルーチンしか呼ばないなら、そのサブルーチンはリエントラントであり、スレッドセーフである。このようなサブルーチンは「純関数; pure function」などと呼ばれることもあり、数学の関数によく似ている。
[編集] スレッドセーフの実現手法
スレッドセーフを実現する方法として以下のようなものがある。
- リエントラント
- リエントラント化することでスレッドセーフを実現できるが、広域変数などを使った状態情報のセーブができない。
- 相互排他
- 共有データへのアクセスを「逐次化」することでスレッドセーフを実現する。ただし、複数の共有データにアクセスする際には十分に注意しなければならない(排他制御参照)。
- スレッドローカルデータ
- 例えばスレッドの識別子(番号)をキーとして広域変数をスレッド毎に持たせることでサブルーチンを超えた範囲で変数を保持できるようにする。各変数にアクセスするサブルーチン自体はリエントラントではないが、特定のスレッドだけが特定の広域変数にアクセスすることが保証できれば、スレッドセーフとなる。
- アトミック操作
- 共有データを何らかのアトミックな操作でアクセスすることで他のスレッドから同時アクセスされないことを保証する。これは一般に特別な命令を必要とするが、ライブラリがそのような機能をサポートしている場合がある。アトミック操作は多くの排他機構の基盤となっている。
一般的にはこれらの手法に以下の手法を結合して使用する。
- 共有データのスレッド固有のコピーを使用し、そのコピーの値で共有データをアトミックにアップデートする。このようにすることでコードの大部分は並行して実行可能となり、必要最小限の部分だけがシリアライズされる。
[編集] 関連項目
[編集] 外部リンク
- スレッドセーフ情報 HP-UX 11i v1.5 におけるスレッドセーフなAPIの一覧
- スレッドセーフ コンポーネント .NET framework(MSDN)
以下、英文
- Article "Thread-safe webapps using Spring" by Steven Devijver
- Thread-safe design
- Article "Design for thread safety" by Bill Venners
- Article "Write thread-safe servlets" by Phillip Bridgham
- Article "Smart Pointer Thread Safety" by Dejan Jelovic