@Mackie が言うように、パイプラインは s でいっぱいになりcmp
ます。Intel はcmp
、別のコアが書き込みを行うときにこれらの をフラッシュする必要がありますが、これはコストのかかる操作です。CPU がフラッシュしない場合は、メモリ順序違反が発生しています。このような違反の例は次のとおりです。
(これは lock1 = lock2 = lock3 = var = 1 で始まります)
スレッド 1:
spin:
cmp lock1, 0
jne spin
cmp lock3, 0 # lock3 should be zero, Thread 2 already ran.
je end # Thus I take this path
mov var, 0 # And this is never run
end:
スレッド 2:
mov lock3, 0
mov lock1, 0
mov ebx, var # I should know that var is 1 here.
まず、スレッド 1 について考えます。
cmp lock1, 0; jne spin
branch が lock1 がゼロでないと予測した場合、パイプラインに追加さcmp lock3, 0
れます。
パイプラインでcmp lock3, 0
lock3 を読み取り、それが 1 であることを確認します。
ここで、スレッド 1 がゆっくりと時間をかけており、スレッド 2 がすぐに実行を開始するとします。
lock3 = 0
lock1 = 0
それでは、スレッド 1 に戻りましょう。
cmp lock1, 0
が最後に lock1 を読み取り、lock1 が 0 であることを発見し、その分岐予測能力に満足しているとしましょう。
このコマンドはコミットされ、何もフラッシュされません。正しい分岐予測は、プロセッサが内部依存関係がないと推測したため、順不同の読み取りがあっても何もフラッシュされないことを意味します。CPU から見ると lock3 は lock1 に依存していないため、これで問題ありません。
これで、cmp lock3, 0
lock3 が 1 に等しいことを正しく読み取った がコミットします。
je end
取られず、mov var, 0
実行されます。
スレッド 3 では、ebx
は 0 です。これは不可能だったはずです。これは、Intel が補正する必要があるメモリ順序違反です。
現在、インテルがその無効な動作を回避するために取っている解決策は、フラッシュすることです。スレッド 2 で実行するlock3 = 0
と、スレッド 1 に lock3 を使用する命令を強制的にフラッシュさせます。この場合のフラッシュは、lock3 を使用するすべての命令がコミットされるまで、スレッド 1 がパイプラインに命令を追加しないことを意味します。スレッド 1cmp lock3
がコミットできる前に、コミットするcmp lock1
必要があります。がcmp lock1
コミットを試みると、lock1 が実際には 1 に等しく、分岐予測が失敗したことが読み取られます。これにより、cmp
が投げ出されます。スレッド 1 がフラッシュされたのでlock3
、スレッド 1 のキャッシュ内の の場所が に設定され0
、スレッド 1 は実行を継続します (待機中lock1
)。スレッド 2 は、他のすべてのコアが使用をフラッシュしたことを通知されるようになりましたlock3
キャッシュを更新したため、スレッド 2 は実行を継続します (その間、スレッド 2 は独立したステートメントを実行しますが、次の命令は別の書き込みであったため、他のコアに保留中のlock1 = 0
書き込みを保持するためのキューがない限り、おそらくハングする必要があります)。
このプロセス全体はコストがかかるため、一時停止します。PAUSE はスレッド 1 を支援します。スレッド 1 は差し迫った分岐の予測ミスから即座に回復でき、正しく分岐する前にパイプラインをフラッシュする必要はありません。PAUSE は同様に、スレッド 1 のフラッシュを待つ必要がないスレッド 2 を支援します (前に述べたように、この実装の詳細についてはよくわかりませんが、スレッド 2 があまりにも多くの他のコアで使用されるロックを書き込もうとすると、スレッド 2 は最終的にはフラッシュを待つ必要があります)。
重要な理解として、私の例ではフラッシュが必要ですが、Mackie の例ではそうではありません。ただし、CPU には知る方法がないため (連続するステートメントの依存関係のチェックと分岐予測キャッシュを除いて、コードをまったく分析しません)、CPU はlockvar
私の場合と同様に、Mackie の例にアクセスする命令をフラッシュします。正確性を保証するため。