マルチスレッドのコンピュータプログラミングでは、関数は、予期しない動作、競合状態、またはデータ破損を引き起こすことなく、複数のスレッドによって同時に呼び出されたりアクセスされたりできる場合にスレッドセーフであると言えます。[ 1 ] [ 2 ]プログラムが共有アドレス空間で複数のスレッドを同時に実行し、各スレッドが他のすべてのスレッドのメモリにアクセスできるマルチスレッドのコンテキストと同様に、スレッドセーフな関数は、意図しない相互作用なしに、すべてのスレッドが適切に動作し、設計仕様を満たすことを保証する必要があります。[ 3 ]
スレッドセーフなデータ構造を作成するためのさまざまな戦略があります。[ 3 ]
異なるベンダーはねじの安全性に関して若干異なる用語を使用していますが、[ 4 ]最も一般的に使用されているねじの安全性の用語は次のとおりです。[ 2 ]
スレッドの安全性を保証するには、通常、さまざまな形式のデッドロックのリスクを防止または制限するための設計手順や、並行処理のパフォーマンスを最大化するための最適化が含まれます。しかし、デッドロックはライブラリ自体とは無関係に、コールバックやアーキテクチャの階層構造の違反によって発生する可能性があるため、常にデッドロックフリーを保証できるとは限りません。
ソフトウェアライブラリは、特定のスレッドセーフティ保証を提供できます。[ 5 ]例えば、同時読み取りはスレッドセーフであることが保証されているかもしれませんが、同時書き込みは保証されていないかもしれません。そのようなライブラリを使用するプログラムがスレッドセーフであるかどうかは、そのプログラムがそれらの保証と整合した方法でライブラリを使用しているかどうかに依存します。
スレッドセーフティを実現するために、競合状態を回避する2つのアプローチを以下に示します。
最初のアプローチ群は、共有状態を回避することに焦点を当てており、以下のものが含まれます。
2つ目のアプローチは同期に関連するもので、共有状態を避けられない状況で使用されます。
以下のJavaコードでは、Javaキーワードsynchronizedによってメソッドがスレッドセーフになります。
class Counter { private int i = 0 ;public synchronized void inc () { i ++ ; } }C言語では、各スレッドは独自のスタックを持ちます。しかし、静的変数はスタック上に保持されず、すべてのスレッドが同時にアクセスします。複数のスレッドが同じ関数を実行中に重なると、あるスレッドが静的変数をチェックしている最中に、別のスレッドがその変数を変更してしまう可能性があります。このような診断が難しい論理エラーは、ほとんどの場合コンパイルと実行が正しく行われるため、競合状態と呼ばれます。これを回避する一般的な方法の1つは、別の共有変数を「ロック」または「ミューテックス」(相互排他)として使用することです。
以下のC言語コードでは、 POSIXヘッダーを呼び出す関数はスレッドセーフですが、リエントラントではありません。
#include <pthread.h>int incrementCounter () { static int counter = 0 ; static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER ;// 一度に1つのスレッドのみがインクリメントできるようにするpthread_mutex_lock ( & mutex );++カウンター;// 他のスレッドがさらにインクリメントする前に値を格納しますint result = counter ;pthread_mutex_unlock ( & mutex );結果を返す; }上記のように、increment_counter共有変数へのすべてのアクセスを同期するためにミューテックスが使用されているため、異なるスレッドから呼び出しても問題ありませんcounter。しかし、この関数が再入可能な割り込みハンドラで使用され、ミューテックスがロックされている間に2つ目の割り込みが発生すると、2つ目のルーチンは永久にハングアップします。割り込み処理によって他の割り込みが無効になる可能性があるため、システム全体に悪影響を及ぼす可能性があります。
同じ関数を、C++11で導入されたロックフリーのアトミック操作を使用して、スレッドセーフかつリエントラントに実装することができます。
import std ;std :: atomicを使用します。int incrementCounter () { static atomic < int > counter ( 0 );// インクリメントは必ずアトミックに実行されますint result = ++ counter ;結果を返す; }{{cite book}}: CS1 maint: postscript (リンク){{cite web}}: CS1 maint: postscript (リンク){{cite web}}: CS1 maint: postscript (リンク)