2011-08-03 22 views
12

参照には、32ビットプロセッサでは4バイト、64ビットプロセッサでは8バイトのメモリが必要であることが知られています。従って、プロセッサは、機械の自然語サイズの増分でメモリへの単一の読み書きが原子的に実行されることを保証する。 Interlocked.ExchangeがInt32に対してと参照型のために必要とされる理由参照とInt32の更新にInterlocked.Exchangeを使用する

public static int Exchange(
    ref int location1, 
    int value 
) 

public static T Exchange<T>(
    ref T location1, 
    T value 
) 
where T : class 

だから、質問は次のとおりです。一方 インタロッククラスの2つの方法があるのですか? アトミックなので単純な代入だけで安全に行うことはできませんでしたか?

答えて

9

原子性だけではありません。また、メモリの可視性に関するものです。変数はメインメモリまたはCPUキャッシュに格納できます。変数がCPUキャッシュにのみ格納されている場合は、別のCPU上で実行されているスレッドには表示されません。以下の例で考えてみます。今、あなたは別のスレッド上のスレッドの「ChangeUsingAssignment」と「読む」と呼ぶ場合

public class Test { 
    private Int32 i = 5; 

    public void ChangeUsingAssignment() { 
     i = 10; 
    } 

    public void ChangeUsingInterlocked() { 
     Interlocked.Exchange(ref i, 10); 
    } 

    public Int32 Read() { 
     return Interlocked.CompareExchange(ref i, 0, 0); 
    } 
} 

を戻り値は5ではなく、10かもしれないが、あなたはChangeUsingInterlockedを呼び出す場合、10を返します「読み取り」予想通り。 「ChangeUsingAssignement」メソッド上記の図において

----------   ------------   ------------------- 
| CPU 1 | --> | CACHE 1 | --> |     | 
----------   ------------  |     | 
             |  RAM  | 
----------   ------------  |     | 
| CPU 2 | --> | CACHE 2 | --> |     | 
----------   ------------   ------------------- 

CACHE 2としないがRAMにするで「立ち往生」値10 GETをもたらすことができます。後でCPU1がそれを読み込もうとすると、RAMから値を取得します。通常の書き込みの代わりにインターロックを使用すると、値10がRAMにすべて到達するようになります。

+0

ありがとうございました。今は十分明確です。 –

+3

これは明らかに1年後ですが、可能であれば、これを見直してもらえますか?このウェブサイトhttp://igoro.com/archive/volatile-keyword-in-c-memory-model-explained/は、C#のすべての書き込みがすでに揮発性であることを暗示しているようです。 – user981225

5

メモリ値とCPUレジスタの内容を交換するのは一般的にアトミックではありません。あなたは両方ともメモリロケーションを読み書きする必要があります。さらに、Interlockedメソッドは、各コアが独自のキャッシュを持ち、潜在的にメインメモリの独自のビューを持つマルチコアコンピュータであっても、操作がアトミックであることを保証します。

+0

しかし、私は古い値を持つ必要はなく、単に新しい値をいくつかの変数に割り当てる必要がある場合。これは書き込みと原子だけです、そうですか? –

+0

@OlegDudnyk元の値を気にしなくても、正しくないと思います。アセンブリ言語でこれを達成する方法を考えてみましょう。srcとdestの変数/値がどこにあるかによって異なりますが、2つの命令の間で2つの命令に変換できます。いくつかのアーキテクチャでは、誰も書き込みメモリを読み取ることができないようにバスをロックすることができます(IAはLOCKプレフィックスを持ちます)。いくつかの命令はアトミックであることが保証されています(IAのXCHG、CMPXCHGなど)。 – codewarrior

8

Interlocked.Exchangeには戻り値があり、置き換えたばかりの値を知ることができます。これは、新しい値を設定して、これらのメソッドが達成する古い値を取得する組み合わせです。

+0

古い値を必要としない場合は、単純に割り当てることができますが、キャッシュを無効にするにはバリア呼び出しも必要です。 –

+0

@Henk:バリアコールの意味をもっと詳しく教えてください。 –

+0

古典的な参照:http://www.albahari。com/threading/ –

4

Interlock.Exchangeは、アトミック操作を実行中にオリジナルの値を返します。全体のポイントは、ロック機構を提供することです。したがって、実際には2つの操作です。元の値は新しい値を設定します。それら2つは一緒に原子ではありません。

+1

しかし、私は古い値を持つ必要はなく、単に新しい値をいくつかの変数に割り当てる必要がある場合。これは書き込みと原子だけです、そうですか? –

+0

@gorik:任意の参照型の変数、または(32ビットマシンの場合)4バイト以下の任意の組み込み値型の変数に対する読み取りまたは書き込み操作の場合は、アトミックであることが保証されています。このシリーズの記事をEric Lippertがチェックしてください。彼らはいくつかの助けになるでしょう:[原子原性、ボラティリティと不変性は異なる、パート1](http://blogs.msdn.com/b/ericlippert/archive/2011/ 05/26 /原子性 - 揮発性 - 不変性 - 異なる - パート - one.aspx) – InBetween

関連する問題