26

Volatile の読み取りと書き込み、および適時性に関する Joe Duffy の投稿を読んでいて、投稿の最後のコード サンプルについて何かを理解しようとしています。

while (Interlocked.CompareExchange(ref m_state, 1, 0) != 0) ;
m_state = 0;
while (Interlocked.CompareExchange(ref m_state, 1, 0) != 0) ;
m_state = 0;
… 

2 番目の CMPXCHG 操作が実行されるとき、メモリ バリアを使用して、m_stateの値が実際に書き込まれた最新の値であることを確認しますか? それとも、プロセッサのキャッシュに既に格納されている値を使用するだけですか? ( m_stateが volatile として宣言されていないと仮定します)。
私の理解が正しければ、CMPXCHG がメモリ バリアを使用しない場合、最初にロックを取得したスレッドがすべてを取得する可能性が高いため、ロック取得手順全体は公平ではありません。次のロックの。私は正しく理解しましたか、それともここで何かを見逃していますか?

編集: 主な問題は、実際に CompareExchange を呼び出すと、m_state の値を読み取ろうとする前にメモリ バリアが発生するかどうかです。そのため、CompareExchange を再度呼び出そうとしたときに、すべてのスレッドに 0 の割り当てが表示されるかどうか。

4

6 に答える 6

27

ロックプレフィックスを持つ x86 命令には、フル メモリ バリアがあります。Abel の回答に示されているように、Interlocked* API と CompareExchanges は、などのlockプレフィックス付きの命令を使用しますlock cmpxchg。したがって、メモリフェンスを意味します。

はい、Interlocked.CompareExchange はメモリ バリアを使用します。

なんで?x86 プロセッサがそうしたからです。Intel のVolume 3A: System Programming Guide Part 1、セクション 7.1.2.2 から:

P6 ファミリ プロセッサの場合、ロックされた操作は、すべての未処理のロードおよびストア操作をシリアル化します(つまり、それらが完了するのを待ちます)。この規則は、1 つの例外を除いて、Pentium 4 および Intel Xeon プロセッサにも当てはまります。弱い順序付けのメモリ タイプ (WC メモリ タイプなど) を参照するロード操作は、シリアル化されない場合があります。

volatileこの議論とは何の関係もありません。これはアトミック操作に関するものです。CPU でのアトミック操作をサポートするために、x86 は以前のすべてのロードとストアが完了することを保証します。

于 2009-11-11T16:57:40.583 に答える
7

同名のWin32 API関数との比較もあるようですが、このスレッドはC#Interlockedクラスの話ばかりです。まさにその記述から、その操作がアトミックであることが保証されています。ここの他の回答で述べられているように、それが「完全なメモリバリア」にどのように変換されるかはわかりませんが、自分で判断してください。

ユニプロセッサ システムでは、特別なことは何も起こらず、命令は 1 つだけです。

FASTCALL_FUNC CompareExchangeUP,12
        _ASSERT_ALIGNED_4_X86 ecx
        mov     eax, [esp+4]    ; Comparand
        cmpxchg [ecx], edx
        retn    4               ; result in EAX
FASTCALL_ENDFUNC CompareExchangeUP

ただし、マルチプロセッサ システムでは、ハードウェア ロックを使用して、他のコアが同時にデータにアクセスするのを防ぎます。

FASTCALL_FUNC CompareExchangeMP,12
        _ASSERT_ALIGNED_4_X86 ecx
        mov     eax, [esp+4]    ; Comparand
  lock  cmpxchg [ecx], edx
        retn    4               ; result in EAX
FASTCALL_ENDFUNC CompareExchangeMP

ところどころ誤った結論が含まれている興味深い読み物ですが、このテーマに関して全体として優れているのは、CompareExchange に関するこのブログ投稿です

ARM の更新

多くの場合、答えは「場合による」です。2.1 より前の ARMにはハーフバリアがあったようです。2.1 リリースでは、この動作は操作の完全なバリアに変更されましたInterlocked

現在のコードはここにあり、CompareExchange の実​​際の実装はここにあります。生成された ARM アセンブリに関する議論と、生成されたコードの例は、前述の PR で見ることができます。

于 2009-11-10T00:18:35.153 に答える
2

インターロックされた関数は、オペランドを解決している間、バスと CPU をストールすることが保証されています。直接の結果は、CPU または別の CPU のスレッド スイッチが実行中にインターロックされた機能を中断しないことです。

C# 関数への参照を渡しているため、基になるアセンブラー コードは実際の整数のアドレスで動作するため、変数アクセスは最適化されません。期待どおりに動作します。

編集: asm 命令の動作をよりよく説明するリンクは次の とおりです: http://faydoc.tripod.com/cpu/cmpxchg.htm
同時にバスを使用しようとする (読み取り: 他の CPU コア) は、待機キューに入れられます。

于 2009-10-17T09:15:44.883 に答える