7

Java の volatile とは異なり、.NET の volatile では、別の場所からの後続の volatile 読み取りを使用して、volatile 書き込みの順序を変更できることが知られています。問題 MemoryBarierがある場合は、それらの間に配置することをお勧めします。またはInterlocked.Exchange、揮発性書き込みの代わりに使用できます。

機能しますがMemoryBarier、高度に最適化されたロックフリー コードで使用すると、パフォーマンスが低下する可能性があります。

少し考えて、ある考えに至りました。私が正しい道を歩んだかどうか、誰かに教えてもらいたい。

したがって、アイデアは次のとおりです。

これら 2 つのアクセス間での並べ替えを防止したいと考えています。

 volatile1 write

 volatile2 read

.NET MM から、次のことがわかります。

 1) writes to a variable cannot be reordered with  a  following read from 
    the same variable
 2) no volatile accesses can be eliminated
 3) no memory accesses can be reordered with a previous volatile read 

書き込みと読み取りの間の不要な並べ替えを防ぐために、書き込み先の変数からダミーの volatile 読み取りを導入します。

 A) volatile1 write
 B) volatile1 read [to a visible (accessible | potentially shared) location]
 C) volatile2 read

このような場合、両方が同じ変数にアクセスするため、 B を A で並べ替えることができず、 CB並べ替えることができませんこれは、2 つの揮発性読み取りを相互に並べ替えることができず、推移的にCをAで並べ替えることができないため です。

そして質問:

私は正しいですか?そのダミーの揮発性読み取りを、そのようなシナリオの軽量メモリバリアとして使用できますか?

4

4 に答える 4

2

すぐに見つかった回答を SO に投稿するのを忘れていました。遅刻しないよりはまし..

プロセッサ (少なくとも x86-x64 の種類) がメモリアクセスを最適化する方法のおかげで、それは不可能であることが判明しました。そのprocsでIntelのマニュアルを読んでいたときに答えを見つけました。例 8-5: 「プロセッサ内転送は許可されています」は疑わしいように見えました。「ストア バッファ フォワーディング」をグーグル検索すると、Joe Duffy のブログ記事が表示されます ( 1 番目2 番目の記事をお読みください)。

書き込みを最適化するために、プロセッサはストア バッファを使用します (書き込み操作のプロセッサ キューごと)。書き込みをローカルにバッファリングすることで、次の最適化を行うことができます。以前にバッファリングされた同じメモリ位置への書き込みからの読み取りを満たし、まだプロセッサを離れていません。この手法は、ストア バッファ フォワーディング (またはストア ツー ロード フォワーディング) と呼ばれます。

この場合の最終結果は、Bでの読み取りがローカル ストレージ (ストア バッファー) から満たされるため、揮発性読み取りとは見なされず、別のメモリ ロケーション ( C )からの揮発性読み取りでさらに順序を変更できるということです。

「揮発性読み取りは互いに並べ替えられない」というルールに違反しているようです。はい、それは違反ですが、非常にまれで風変わりな違反です。なぜそれが起こったのですか?おそらく、.NET (およびその JIT コンパイラ) が登場してから数年後に、Intel がプロセッサのメモリ モデルに関する最初の正式なドキュメントをリリースしたためです。

したがって、答えは次のとおりです。いいえ、ダミーの読み取り ( B ) はACの間の並べ替えを妨げず、軽量のメモリ バリアとして使用することはできません。

于 2015-09-24T12:07:48.167 に答える
0

編集C# 仕様から導き出した結論は間違っています。以下を参照してください。編集終了

私は確かに「承認された」人ではありませんが、メモリモデルを正しく理解していないと思います。

C# 仕様、セクション §10.10実行順序、105 ページの 3 番目の箇条書きを引用します。

副作用の順序は、揮発性の読み取りと書き込みに関して保持されます。

揮発性の読み取りと書き込みは「副作用」として定義され、この段落では、副作用の順序が保持されると述べています。

したがって、質問全体が誤った仮定に基づいていることを理解しています。揮発性の読み取りと書き込みは並べ替えられません。

不揮発性メモリの操作に関して、揮発性の読み取りと書き込みはハーフフェンスにすぎないという事実に混乱していると思います。

この記事を編集: The C# Memory Model in Theory and Practice, Part 2は正反対のことを述べており、揮発性読み取りが無関係な揮発性書き込みを超えて移動できるという主張をサポートしています。推奨される解決策は、重要な場所に MemoryBarrier を導入することです。

以下の Daniel によるコメントでは、CLI 仕様は C# 仕様よりも具体的であり、この並べ替えが可能であるとも述べています。

ここで、上で引用した C# の仕様が紛らわしいことに気付きました。しかし、x86 では、揮発性メモリ アクセスと通常のメモリ アクセスに同じ命令が使用されることを考えると、それらが同じハーフ フェンスの並べ替えの問題の影響を受けることは完全に理にかなっています。編集終了

于 2013-06-01T19:06:19.377 に答える
0

Brian Gideon からの受け入れられた回答に同意しないでください。

OmariO問題に対するあなたの解決策 (ダミーの読み取り) は、私には完全に正しいように見えます。あなたが正しく述べたように、変数への書き込みは、同じ変数からの次の読み取りで並べ替えることはできません。その並べ替えが可能である場合、シングルスレッドのケースではコードが正しくなくなります (読み取り操作は、前の書き込み操作によって書き込まれた値とは異なる値を返す可能性があります)。つまり、メモリ モデルの基本的な規則に違反することになります。つまり、プログラムのシングル スレッド実行を論理的に変更してはなりません。

Brian と Omario の皆さん、メモリ操作と取得/解放セマンティクスおよびメモリ フェンスの取得/解放を混同しないでください。たとえば、読み取り取得操作は取得フェンスと同じではありません。これらのセマンティクスは似ていますが、両者の違いは非常に重要です。私が知っているその用語の最良の説明は、Jeff Preshing の素晴らしいブログにあります:
Acquire and Release Semantics
Acquire and Release Fences

于 2013-11-28T18:25:05.190 に答える