3

私は Herb の素晴らしい「原子兵器」の講演を 2 回目で探しており、全記憶モデル / 逐次的一貫性の物語を経る概念に頭を悩ませようとしています。概念レベルで気になることが 1 つあります。この話から得た教訓の 1 つは、atomics を使用することで、他の方法ではコンパイラーが検出できないスレッド間の相互作用について、コンパイラーに「ヒント」を与えることができるということです。

そこで、次のシナリオについて心配し始めました。

int local_copy_of_shared_var = shared_var;
if (local_copy_of_shared_var > some_threshold)
{
   DoSomething();
}
... Do some work

if (local_copy_of_shared_var > some_threshold)
{
   DoSomethingElse();
}

この場合、Hans Bohem が「「無害な」データ競合を含むプログラムを誤ってコンパイルする方法」で指摘したように (変数名は上記のスニペットに合わせて調整されています):

2 つのテストの間に local_copy_of_shared_var を含むレジスタをスピルする必要があるとコンパイラが判断した場合、値の格納を回避し (結局のところ、これは単に shared_var のコピーにすぎません)、代わりに単純に shared_var の値を再読み取りすることを決定する可能性があります。 local_copy_of_shared_var を含む 2 番目の比較。

[...] 核となる問題は、変数値は明示的な代入なしでは非同期に変更できないという仮定をコンパイラが利用することから生じます。私たちの設定のようにデータ競合が言語仕様で許可されていない場合、そのような仮定は完全に正当です。データ競合がなければ、このような非同期変更は不可能です

ここで、アトミック (デフォルトの seq_cst メモリー順序付け) はデータ競合がないことを保証する必要があり、それらは異なるスレッド間でそのような変数に相互作用があるというコンパイラーへの「ヒント」であるため、前述のアトミックを使用すると主張することができますスニペットは、コンパイラがshared_varからそのような「再読み取り」を挿入するのを防ぎ、代わりにlocal_copy_of_shared_varを「ワンショット」スナップショットと見なして、2 つのテスト間の矛盾を回避しますか?

常識に基づいて、ここでアトミックを使用するだけで、2 つのテスト間でlocal_copy_of_shared_varが更新されないようにコンパイラが対策を講じることが保証されるとは思わないため、私の推論には何か問題があると思います。一方、Herb が講演で述べているように、メモリ モデルは、アトミックを使用する場合にコンパイラによって偽のメモリ操作が追加されないことを保証するようになりました。 "安全"。私は非常に混乱しており、コミュニティからの意見を聞きたいと思っています。私の推論にバグがある場合は、おそらく修正してもらいたいと思っています。

4

1 に答える 1

3

コンパイラはコード変換を意のままに行うだけではなく、 as-ifルールに従う必要があります。これは基本的に、生成されたプログラムが、入力プログラムに記述されたコードを実行するかのように動作する必要があることを示しています。あなたが参照する最適化を許容できるものにするのは、古い学校の C++03 でも、 の値がshared_varへの 2 つの参照の間で変化しないことをコンパイラが証明できなければならないということlocal_copy_of_shared_varです。通常、これは、介在するすべてのコードがコンパイラに表示され、への割り当てが含まれていないことを意味しますshared_var

shared_varが非アトミック型の場合、この最適化は C++11 でも有効です。これはshared_var、別のスレッドで を同時に変更するとデータ競合が発生し、未定義の動作になるためです。shared_varC++11 をアトミックにすることは、別のスレッドによって変更される可能性があるため、2 つの参照の間で が変更されないことを証明できないshared_varこと、およびこの特定の最適化がas-ルールの場合。

TLDR: 一般に、コンパイラは、データ競合を導入するため、アトミックに偽の読み取りを導入することを禁じられています。

于 2013-06-18T20:40:06.540 に答える