3

これは単純な問題ですが、なぜメモリバリアが必要なのかを読んだ後、私はそれについて非常に混乱しています。

以下の例では、さまざまなスレッドが Increment と Counter を繰り返し呼び出していると想定しています。

class Foo{
    int _counter=0;
    public int Counter 
    {
        get { return _counter; }
    }

    public void Increment()
    {
        Interlocked.Increment(ref _counter);
    }
}

誤解していたらごめんなさいなぜメモリバリアが必要なのですか? しかし、_counter の値を読み取るときに、上記のクラスが鮮度を保証していない可能性があることを示唆しているようです。Counter プロパティに繰り返しアクセスしているスレッドは、Counter の古い値で永遠に動かなくなる可能性があります (レジスタにキャッシュされているため)。

必要になる前にメモリバリアまたはロックはreturn _counter;ありますか?

4

1 に答える 1

8

return _counter; の前のメモリーバリアまたはロックです。必要?

そのとおり。次のコードを検討してください。

while (foo.Counter == 0)
{
  // Do something
}

問題は、ループ内の内容が十分に単純な場合、C# コンパイラ、JIT コンパイラ、またはハードウェアがこの方法でコードを最適化することです。

int register = foo._counter;
while (register == 0)
{
  // Do something
}

またはこれさえ。

if (foo._counter == 0)
{
  START: 
  // Do something
  goto START;
}

プロパティがおそらくインライン化されることを暗示する方法として_counter代わりに使用していることに注意してください。Counter次に、さらに重要なことに、JIT コンパイラーは_counterループの外側の読み取りを「リフト」して、一度だけ読み取られるようにすることができます。

メモリ バリアは、それ自体が鮮度を保証するものではありません。それらが行うことは、メモリへの読み取りと書き込みの順序を変更する特定のソフトウェアまたはハードウェアの最適化を防ぐことです。鮮度の保証は、実際には副作用です。

したがって、Counterプロパティをまとめると、次のようになります。

public int Counter 
{
    get { return Interlocked.CompareExchange(ref _counter, 0, 0); }
}
于 2012-03-23T13:27:34.887 に答える