14

Joe Duffy、CLR 2.0+メモリモデルを説明する6つのルールを示します(これは実際の実装であり、ECMA標準ではありません)これを理解するための試みを、主にラバーダッキングの方法として書き留めていますが、間違えた場合私の論理では、少なくともここの誰かが私に悲しみを引き起こす前にそれを捕まえることができるでしょう。

  • ルール1:ロードとストア間のデータ依存性が侵害されることはありません。
  • ルール2:すべてのストアにはリリースセマンティクスがあります。つまり、ロードまたはストアが1つ後に移動することはありません。
  • ルール3:すべての揮発性ロードは取得されます。つまり、ロードまたはストアが1つ前に移動することはできません。
  • ルール4:ロードとストアがフルバリアを超えることはできません(例:Thread.MemoryBarrier、lockacquire、Interlocked.Exchange、Interlocked.CompareExchangeなど)。
  • ルール5:ヒープへのロードとストアは導入されない場合があります。
  • ルール6:ロードとストアは、同じ場所から/に隣接するロードとストアを合体する場合にのみ削除できます。

私はこれらのルールを理解しようとしています。

x = y
y = 0 // Cannot move before the previous line according to Rule 1.

x = y
z = 0
// equates to this sequence of loads and stores before possible re-ordering
load y
store x
load 0
store z

これを見ると、ロード0はロードyの前に移動できるように見えますが、ストアはまったく再注文されない可能性があります。したがって、スレッドがz == 0を認識している場合、x==yも認識します。

yが揮発性の場合、負荷0は負荷yの前に移動できません。そうでない場合は移動できます。揮発性の店舗には特別な特性はないようです。店舗を相互に再注文することはできません(これは非常に強力な保証です!)

完全な障壁は、砂の中の線のようなもので、積み込みや保管を移動することはできません。

ルール5が何を意味するのかわかりません。

ルール6は、次のことを意味すると思います。

x = y
x = z

次に、CLRがyへのロードとxへの最初のストアの両方を削除することができます。

x = y
z = y
// equates to this sequence of loads and stores before possible re-ordering
load y
store x
load y
store z
// could be re-ordered like this
load y
load y
store x
store z
// rule 6 applied means this is possible?
load y
store x // but don't pop y from stack (or first duplicate item on top of stack)
store z

yが揮発性だった場合はどうなりますか?上記の最適化の実行を禁止するルールはありません。2つの同一条件間のlock()により、負荷が隣接する位置に移動するのを防ぐため、これはダブルチェックロックに違反しません。ルール6によれば、負荷を排除できるのはこのときだけです。

ですから、ここではルール5以外はすべて理解していると思います。誰かが私を啓発したい(または私を訂正するか、上記のいずれかに何かを追加したいですか?)

4

1 に答える 1

11

Joe Duffyが、Windowsでの同時プログラミングのpp517-18に関するルール5について説明しています。

負荷が発生する可能性がある場合の例として、次のコードを検討してください。

MyObject mo = ...;
int f = mo.field;
if (f == 0)
{
    // do something
    Console.WriteLine(f);
}

変数fへのmo.fieldの最初の読み取りから、その後のConsole.WriteLineでのfの使用までの期間が十分に長い場合、コンパイラーは、mo.fieldを2回再読み取りする方が効率的であると判断する場合があります。... moがヒープオブジェクトであり、スレッドがmo.fieldに同時に書き込みを行っている場合、これを行うと問題が発生します。ifブロックには、fに読み込まれた値が0のままであると想定するコードが含まれている可能性があり、読み取りを導入すると、この想定が破られる可能性があります。揮発性変数に対してこれを禁止することに加えて、.NETメモリモデルは、GCヒープメモリを参照する通常の変数に対してもこれを禁止します。

はこれが重要な1つの重要な場所についてブログを書きました:イベントを発生させるための標準的なパターン。

EventHandler handler = MyEvent;
if (handler != null)
    handler(this, EventArgs.Empty);

別のスレッドでイベントハンドラーを削除する際の問題を防ぐために、の現在の値を読み取り、MyEventそのデリゲートがnullでない場合にのみイベントハンドラーを呼び出します。

MyEventヒープからの読み取りが導入される可能性がある場合、コンパイラー/ JITは、競合状態を導入するローカルを使用するよりも、再度読み取る方がよいと判断する可能性があります。

于 2010-05-31T04:13:13.233 に答える