変数とこれらの変数を変更する命令で構成されるプログラム、および同期プリミティブ(モニター、ミューテックス、Javaの同期またはC#のロック)が与えられた場合、そのようなプログラムがスレッドセーフであることを証明できますか?
スレッドセーフティやレース条件などを記述するための正式なモデルさえありますか?
変数とこれらの変数を変更する命令で構成されるプログラム、および同期プリミティブ(モニター、ミューテックス、Javaの同期またはC#のロック)が与えられた場合、そのようなプログラムがスレッドセーフであることを証明できますか?
スレッドセーフティやレース条件などを記述するための正式なモデルさえありますか?
回答:
プログラムが「スレッドセーフ」であることを証明することは困難です。ただし、「データ競合」という用語を具体的かつ正式に定義することは可能です。また、プログラムの特定の実行の実行トレースに、トレースのサイズに比例した時間のデータレースがあるかどうかを判断できます。このタイプの分析は、少なくとも1988年まで遡ります 。BartonP. Miller、Jong-Deok Choi、「A Parallel Machinesの効率的なデバッグのメカニズム」、会議。Prog。ラング。Dsgn。とインプリ。(PLDI-1988):135-144。
実行のトレースを前提として、まず、トレース内のイベント間の発生前の半順序を定義します。与えられた二つの事象とBその後、同じスレッド上で発生< BまたはB <。(同じスレッド上のイベントは、プログラミング言語の順次セマンティクスによって与えられる全体の順序を形成します。) 同期イベント(たとえば、これらはmutexの取得と解放である可能性があります)は、部分的な順序の前に追加のスレッド間発生を与えます。(スレッドSがミューテックスを解放してからスレッドTがそのミューテックスを獲得する場合、解放が獲得の前に行われると言います。)
次に、2つのデータアクセス(同期変数ではない変数の読み取りまたは書き込み)とbが同じメモリ位置にあるが、異なるスレッドによるものであり、aまたはbのいずれかが書き込み操作である場合、データがあると言う-間の競争とBどちらかの< BもB <。
C ++ 11標準は良い例です。(関連セクションは、オンラインで利用可能なドラフト仕様の1.10です。)C ++ 11は、同期オブジェクト(ミューテックス、およびatomic<>
型で宣言された変数)と他のすべてのデータを区別します。C ++ 11仕様では、マルチスレッドプログラムのトレース上のデータアクセスについて、データアクセスがすべてデータ競合がない場合、シーケンシャルに一貫しているかのように推論できると述べています。
Helgrindツール(Valgrindの一部)は、いくつかの商用ツール(Intel Inspector XEなど)と同様に、この種のビフォアビフォアベースのデータ競合検出を実行します。最新のツールのアルゴリズムは、すべてのスレッドと同期に関連付けられたベクトルクロックの維持に基づいています。オブジェクト。データレースの検出にベクトルクロックを使用するこの手法は、Michiel Ronsseによって開拓されたと思います。Koen De Bosschere:「RecPlay:完全に統合された実用的な記録/再生システム」、ACM Trans。計算。システム。17(2):133-152、1999。
これは、並列処理の一種の「アキレスヒール」である競合状態を除外する限り、プログラムの正確さを保証するのが非常に難しい領域です。プログラムを正確にするための最良のアプローチは、通常、低レベルのプリミティブを回避し、スレッドの同期を保証する高レベルのデザインパターン(ライブラリなど)を操作することです。Hoareがシーケンシャルプロセスを通信する 1つのモデルCSPがあり、開発者が自分自身を「フレームワーク」に制限することを考えると、正確性のいくつかの証拠があります。これは、UNIXの「パイプとフィルタ」といくつかの概念的な類似性と年代順の起源/重複がありますが、(まだ?)2つの間に直接のリンクはありません。
設計パターンを通じて並列化の正確さを改善しようとする他の2つのフレームワークであり、この目的のための標準/既知のアルゴリズム/設計パターンのほとんどを備えています。