問題タブ [mesi]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c# - 標準の C# イベント呼び出しパターンがメモリ バリアやキャッシュの無効化なしでスレッド セーフなのはなぜですか? 同様のコードはどうですか?
C# では、これはスレッド セーフな方法でイベントを呼び出すための標準コードです。
場合によっては別のスレッドで、コンパイラによって生成された add メソッドが使用Delegate.Combine
して新しいマルチキャスト デリゲート インスタンスを作成し、それをコンパイラによって生成されたフィールドに設定します (インターロックされた比較交換を使用)。
(注: この質問の目的のために、イベント サブスクライバーで実行されるコードは気にしません。削除に直面してもスレッドセーフで堅牢であると仮定します。)
私自身のコードでは、次の行に沿って同様のことをしたいと考えています。
this.memberFoo
別のスレッドで設定できる場所。(これは 1 つのスレッドなので、インターロックする必要はないと思いますが、ここに副作用があるのではないでしょうか?)
Foo
(そして、明らかに、それがこのスレッドで使用されている間は積極的に変更しないように「十分に不変」であると仮定します。)
これで、これがスレッドセーフであるという明白な理由がわかりました。参照フィールドからの読み取りはアトミックです。ローカルにコピーすることで、2 つの異なる値を取得しないことが保証されます。(どうやら.NET 2.0 からのみ保証されているようですが、正常な .NET 実装では安全だと思いますか?)
しかし、私が理解していないのは、参照されているオブジェクトインスタンスによって占有されているメモリはどうですか? 特にキャッシュの一貫性に関しては? 「ライター」スレッドが 1 つの CPU でこれを行う場合:
new が割り当てられるメモリが、初期化されていない値で、「リーダー」が実行されている CPU のキャッシュにないことを保証するものは何Foo
ですか? localFoo.baz
(上記)がガベージを読み取らないことを保証するものは何ですか? (そして、これはプラットフォーム間でどの程度保証されていますか?Monoで?ARMで?)
新しく作成された foo がたまたまプールから取得された場合はどうなるでしょうか。
これは、メモリの観点から見ると、新しい割り当てと同じように見えますが、.NET アロケータが最初のケースを機能させる魔法を使っているのではないでしょうか?
これを尋ねる際の私の考えは、メモリバリアが必要になるということです-読み取りが依存していることを考えると、メモリアクセスを移動できないほどではありませんが、キャッシュの無効化をフラッシュするためのCPUへの信号として.
これの私の情報源はウィキペディアです。
(おそらく、ライタースレッドのインターロック比較交換がリーダーのキャッシュを無効にするのではないかと推測するかもしれません。それとも、すべての読み取りが無効化の原因になるのでしょうか?それとも、ポインターの逆参照が無効化の原因になるのでしょうか?私は特に、プラットフォーム固有のこれらのことがどのように聞こえるかを懸念しています。)
更新:質問がCPUキャッシュの無効化と.NETが提供する保証(およびそれらの保証がCPUアーキテクチャにどのように依存するか)に関するものであることをより明確にするために:
- フィールド
Q
(メモリの場所) に格納された参照があるとします。 - CPU A (ライター) では、メモリ位置 でオブジェクトを初期化し、へ
R
の参照を書き込みますR
Q
- CPU B (リーダー) では、フィールドを逆参照
Q
し、メモリの場所を取得します。R
- 次に、CPU Bで、値を読み取ります。
R
GC がどの時点でも実行されていないと仮定します。他に興味深いことは何も起こりません。
質問: Aが初期化中にそれを変更する前から、 Bのキャッシュに存在することを妨げているものは何ですか? R
Bが最初にどこにあるかを知るために新しいバージョンを取得しているにもかかわらず、 Bがそれから読み取ったときに古い値を取得します? R
Q
R
(別の言い方: への変更がR
CPU Bに見える時点またはその前に、変更をCPU BQ
に見えるようにするもの。)
(そして、これは で割り当てられたメモリ、または任意のメモリにのみ適用されますnew
か?)+
注:ここに自己回答を投稿しました。
caching - あるプロセッサから別のプロセッサのキャッシュへの直接アクセスを提供できないのはなぜですか?
NUMA アーキテクチャ (不均一メモリ アクセス) では、各プロセッサが独自の第 1 レベル キャッシュを持っているため、プロセッサ通信用のプロトコル (MESI) があります。しかし、各プロセッサを他のプロセッサのキャッシュに直接接続できないのはなぜでしょうか? 「接続が単に十分に速くない」と読みましたが、それはあまり説明しませんでした.
ありがとう。
caching - ライトスルー ポリシーのキャッシュが使用されている場合、関連する MESI プロトコルの状態はどれですか?
キャッシュ コヒーレンシ プロトコルに関する講義のスライドを読んでいるときに、次の質問に出くわしました。
I (Invalid)とS (Shared Unmodified)という答えも与えられました。
いずれにせよ、ライトスルー ポリシーのキャッシュは変更をメイン メモリに伝達するため、状態M (Modified Exclusive)は関係ないことを理解しています。
状態E (Exclusive Unmodified)は関係ありません。置換を伴う排他的読み取りミスが発生した場合にのみ発行されるためです (さらに読み取りヒットが発生しても保持されます)。
誰かが与えられた答えを説明できますか?
c++ - 複数のスレッド間でデータを共有する MESI コスト
別のスレッドが書き込んでいる変数を読み取る際のキャッシュ コヒーレンシ (MESI) コストを測定したいと考えています。次のテストを思いつきましたが、読み取りには平均で 2 サイクルしかかからないことが報告されています。
私のテストは間違っていますか?誰かがそれを改善するのを手伝ってくれませんか?
編集: 私の理解では、MESI は C++ のアトミック型とは何の関係もありません。MESI は、キャッシュ ラインが複数の CPU コア間で一貫していることを保証します。したがって、このテストではアトミックを使用していません。
これは、2 番目のグローバル変数がある場合の偽共有の問題と非常によく似ています。これらは両方とも同じキャッシュ ラインを占有しますが、異なるスレッドがそれぞれに書き込みます。各変数は 1 つのスレッドによって書き込まれるのに、なぜアトミックを使用するのでしょうか?
caching - MESI プロトコルに排他的状態が必要な理由
現在、キャッシュの一貫性を学んでいますが、MSI もうまく機能していると思うので、MESI プロトコルの Exclusive 状態の機能がよくわかりません。
multithreading - マルチコアおよびマルチプロセッサ アーキテクチャでキャッシュ コヒーレンスはどのように機能しますか?
私の理解を説明し、その正確性を確認するか、私を訂正してください:
- 効率的なキャッシュの一貫性を可能にする MESI プロトコルがあります ( https://en.wikipedia.org/wiki/MESI_protocol )。最先端のメカニズムです。
- 単一プロセッサの複数のコアの場合、MESI は、プロセッサのコア間で共有される L3 キャッシュを介して動作します。
- 複数のプロセッサ (共有 L3 なし) の場合、MESI はメイン メモリを介して動作します。
- 複数のスレッドによって読み書きされるグローバル変数を使用する場合、volatile型指定子を使用して、望ましくない最適化を防ぎ、レジスター( L1-3 キャッシュではなく) でのキャッシュを防ぎます。したがって、値がレジスタではなくキャッシュまたはメイン メモリにある場合、MESI は、スレッドがグローバルの正しい値を認識できるように作業を行います。
caching - MESI プロトコル。キャッシュミスで書き込みます。なぜメインメモリ値のフェッチが必要なのですか?
書き込みミスポリシーの割り当てによる書き込みのMESIプロトコル実装について疑問に思っています。書き込み要求があり、他のキャッシュ ラインのコピーがない状態でキャッシュ ミスが発生したとします。この図は、次のステップがメイン メモリ (または L2 キャッシュ) から値をフェッチし、それを格納して、キャッシュ ラインを M (変更済み) としてマークすることであることを示しています。その後、新しい値がキャッシュブロックに格納されると思います。問題は、なぜメイン メモリからデータをフェッチするステップが必要なのかということです。I (無効) 状態の最初に見つかったキャッシュ ラインに新しい値を単純に書き込んだり、最も古いキャッシュ ラインを置き換えて M (変更済み) としてマークしたりできないのはなぜですか?
ご協力ありがとうございました!