10

変数「counter」があり、Interlockedを使用して「counter」の値にアクセスして設定するスレッドがいくつかあるとします。

int value = Interlocked.Increment(ref counter);

int value = Interlocked.Decrement(ref counter);

Interlockedによって行われた変更は、すべてのスレッドで表示されると思いますか?

そうでない場合は、すべてのスレッドで変数を同期させるにはどうすればよいですか?

編集:誰かが私に揮発性物質を使用するように提案しました。しかし、「カウンター」を揮発性として設定すると、「揮発性フィールドへの参照は揮発性として扱われません」というコンパイラの警告が表示されます。

オンラインヘルプを読んだとき、「通常、揮発性フィールドはrefまたはoutパラメーターを使用して渡されるべきではありません」と書かれていました。

4

5 に答える 5

7

x86 CPU の InterlockedIncrement/Decrement (x86 の lock add/dec) は、すべてのスレッドに可視性を与えるメモリ バリアを自動的に作成します (つまり、すべてのスレッドは、シーケンシャル メモリの一貫性のように、その更新を順番通りに見ることができます)。メモリバリアは、保留中のすべてのメモリロード/ストアを完了させます。volatileC# と Java (および一部の C/C++ コンパイラ)volatileはメモリ バリアを作成することを強制しますが、この質問とは関係ありません。ただし、連動動作はすでにCPUによるメモリバリアを持っています。

また、stackoverflowの別の回答もご覧ください。

C# の InterlockedIncrement/Decrement は、x86 の lock add/dec への固有のマッピングであると想定していることに注意してください。

于 2010-01-26T19:16:38.223 に答える
7

Interlocked によって行われた変更は、すべてのスレッドで表示されると思いますか?

これは、値の読み取り方によって異なります。「ちょうど」それを読んだ場合、いいえ、揮発性としてマークしない限り、これは他のスレッドで常に表示されるとは限りません。ただし、それは迷惑な警告を引き起こします。

別の方法として (そして IMO として非常に好ましい)、別のインターロック命令を使用して読み取ります。これにより、常にすべてのスレッドで更新された値が表示されます。

int readvalue = Interlocked.CompareExchange(ref counter, 0, 0);

読み取った値を返し、それが 0 の場合は 0 と交換します。

動機: 警告は、何かが正しくないことを示唆しています。2 つの手法 (揮発性とインターロック) を組み合わせることは、これを行うための意図した方法ではありませんでした。

更新:「揮発性」を使用せずに信頼性の高い 32 ビット読み取りを行う別のアプローチは、この回答Thread.VolatileReadで提案されているように使用することです。この Connect issueなど、32ビット読み取りの使用について私が完全に間違っているという証拠もいくつかありますが、その区別は本質的に少し衒学的であるかどうか疑問に思います.Interlocked

私が本当に言いたいのは、この回答を唯一の情報源として使用しないでください。私はこれについて疑問を持っています。

于 2010-01-26T16:08:13.080 に答える
3

実際、そうではありません。を安全に変更したい場合counterは、正しいことを行っています。ただし、直接読み取りたい場合はcounter、 として宣言する必要がありますvolatilecounterそれ以外の場合、コンパイラはそれが変更されると信じる理由がありません。これは、Interlocked操作が認識できないコード内にあるためです。

于 2009-02-05T17:20:43.643 に答える
1

Interlocked は、一度に 1 つのスレッドだけが値を更新できるようにします。他のスレッドが (キャッシュされた値ではなく) 正しい値を読み取れるようにするには、揮発性としてマークします。

public volatile int カウンター。

于 2009-02-05T17:10:44.600 に答える