次のコードを検討してください。
bool done = false;
void Thread1() {
while (!done) {
do_something_useful_in_a_loop_1();
}
do_thread1_cleanup();
}
void Thread2() {
do_something_useful_2();
done = true;
do_thread2_cleanup();
}
これら 2 つのスレッド間の同期は、ブール変数 done を使用して行われます。これは、2 つのスレッドを同期する間違った方法です。
x86 では、最大の問題はコンパイル時の最適化です。
do_something_useful_2() のコードの一部は、コンパイラによって「done = true」の下に移動できます。do_thread2_cleanup() のコードの一部は、コンパイラによって "done = true" の上に移動できます。do_something_useful_in_a_loop_1() が「done」を変更しない場合、コンパイラは Thread1 を次のように書き換える可能性があります。
if (!done) {
while(true) {
do_something_useful_in_a_loop_1();
}
}
do_thread1_cleanup();
そのため、Thread1 は終了しません。
x86 以外のアーキテクチャでは、キャッシュ効果または順不同の命令実行により、他の微妙な問題が発生する可能性があります。
ほとんどの人種検出器は、そのような人種を検出します。
また、ほとんどの動的競合検出器は、この bool と同期することを意図したメモリ アクセスでのデータ競合を報告します。
(つまり、do_something_useful_2() と do_thread1_cleanup() の間)
このような競合を修正するには、コンパイラやメモリ バリアを使用する必要があります (専門家でない場合は、単にロックを使用してください)。