スピンは確かに優れていますが、 DmitriyV'jukovによるRelacyRaceDetectorも検討してください。これは、非ブロッキング(待機/ロックフリー)アルゴリズムを含む並行アルゴリズムを検証するために設計されています。それはオープンソースであり、自由にライセンスされています。
RelacyはPOSIXおよびWindows同期プリミティブ(ミューテックス、条件変数、セマフォ、CriticalSections、win32イベント、Interlocked *など)を提供するため、実際のC++実装を検証のためにRelacyにフィードできます。PromelaやSpinのように、アルゴリズムの別のモデルを開発する必要はありません。
RelacyはC++0x std::atomic
(winの明示的なメモリ順序付け!)を提供するため、プリプロセッサ#defines
を使用して、Relacyの実装と独自のプラットフォーム固有のアトミック実装(tbb :: atomic、boost :: atomicなど)のどちらかを選択できます。
スケジューリングは制御可能です。ランダム、コンテキストバウンド、および完全検索(すべての可能なインターリーブ)が利用可能です。
これがRelacyプログラムの例です。注意すべきいくつかのこと:
- は
$
、実行情報を記録するRelacyマクロです。
rl::var<T>
検証の一部として考慮する必要がある「通常の」(非アトミック)変数にフラグを立てます。
コード:
#include <relacy/relacy_std.hpp>
// template parameter '2' is number of threads
struct race_test : rl::test_suite<race_test, 2>
{
std::atomic<int> a;
rl::var<int> x;
// executed in single thread before main thread function
void before()
{
a($) = 0;
x($) = 0;
}
// main thread function
void thread(unsigned thread_index)
{
if (0 == thread_index)
{
x($) = 1;
a($).store(1, rl::memory_order_relaxed);
}
else
{
if (1 == a($).load(rl::memory_order_relaxed))
x($) = 2;
}
}
// executed in single thread after main thread function
void after()
{
}
// executed in single thread after every 'visible' action in main threads
// disallowed to modify any state
void invariant()
{
}
};
int main()
{
rl::simulate<race_test>();
}
通常のコンパイラ(Relacyはヘッダーのみ)でコンパイルし、実行可能ファイルを実行します。
struct race_test
データレース
反復:8
実行履歴:
[0] 0:アトミックストア、value = 0、(prev value = 0)、order = seq_cst、race_test :: before、test.cpp(14)
[1] 0:store、value = 0、race_test :: before、test.cpp(15)
[2] 0:ストア、値= 1、race_test :: thread、test.cpp(23)
[3] 0:アトミックストア、value = 1、(prev value = 0)、order = Relaxed、race_test :: thread、test.cpp(24)
[4] 1:アトミックロード、value = 1、order = Relaxed、race_test :: thread、test.cpp(28)
[5] 1:store、value = 0、race_test :: thread、test.cpp(29)
[6] 1:race_test :: thread、test.cpp(29)でデータ競合が検出されました
スレッド0:
[0] 0:アトミックストア、value = 0、(prev value = 0)、order = seq_cst、race_test :: before、test.cpp(14)
[1] 0:store、value = 0、race_test :: before、test.cpp(15)
[2] 0:ストア、値= 1、race_test :: thread、test.cpp(23)
[3] 0:アトミックストア、value = 1、(prev value = 0)、order = Relaxed、race_test :: thread、test.cpp(24)
スレッド1:
[4] 1:アトミックロード、value = 1、order = Relaxed、race_test :: thread、test.cpp(28)
[5] 1:store、value = 0、race_test :: thread、test.cpp(29)
[6] 1:race_test :: thread、test.cpp(29)でデータ競合が検出されました
Relacyの最近のバージョンでは、そのようなことに興味がある場合は、JavaおよびCLIメモリモデルも提供されています。