Paul E. McKenney の Memory Barriers を読ん でいます。私は、すべてを無意味にし、何も理解していないと思わせる一文に出くわします。例を示しましょう
void foo(void)
{
a = 1; #1
b = 1; #2
}
void bar(void)
{
while (b == 0) continue; #3
assert(a == 1); #4
}
この 2 つの関数が異なるプロセッサで実行されているとします。ここで、最初のプロセッサが「a」へのストアをキューに格納し、b 命令のストアに進むため、2 番目のプロセッサによる b #2 へのストアの後に、a #1 へのストアが表示される可能性があります。OK、問題ありません。#1 と #2 の間の行に書き込みフェンスを追加しますが、このコードはまだ失敗する可能性があります。これは、2 番目のプロセッサが無効化メッセージをキューに入れる可能性があるためです。 #4 と #4 の間の線。
void foo(void)
{
a = 1; #1
write_memory_barrier();
b = 1; #2
}
void bar(void)
{
while (b == 0) continue; #3
read_memory_barrier();
assert(a == 1); #4
}
これにより、2 番目のプロセッサがキューに入れられたすべてのメッセージを処理し (a を無効化)、#4 の最初のプロセッサに read MESI メッセージを送信して再度読み取るようになります。わかった。次に記事は言う
そのため、多くの CPU アーキテクチャは、これら 2 つのいずれか一方のみを実行する、より弱いメモリ バリア命令を提供します。大まかに言えば、「読み取りメモリ バリア」は無効キューのみをマークし、「書き込みメモリ バリア」はストア バッファのみをマークします。本格的なメモリバリアは両方を行います。
素晴らしい、それは明らかですが、その後、私はこれを見ます
この結果、読み取りメモリ バリアは、それを実行する CPU でのみロードを命令するため、読み取りメモリ バリアに先行するすべてのロードは、読み取りメモリ バリアに続くすべてのロードの前に完了したように見えます。同様に、書き込みメモリ バリアは、書き込みメモリ バリアの前にあるすべてのストアが、書き込みメモリ バリアに続くストアの前に完了したように見えるように、ストアを実行する CPU でのみストアを注文します。
それで
読み取りメモリ バリアに先行するすべてのロードは、読み取りメモリ バリアに続くすべてのロードの前に完了したように見えます。
それは、前に説明したことすべてを混同します。どういう意味ですか?"a" #4 のロードの前に、関数 "bar" のどのロードを完了する必要がありますか? オブジェクト「a」が配置されているキャッシュラインを無効にすることができなかったため、プロセッサが古い値を読み取る可能性があるという理由だけで、この関数のメモリバリアなしでアサートが失敗する可能性があることを理解しています。
詳細な説明は本当に役に立ちます。私は一日中理解しようとしています。
よろしくお願いします。