2016-12-06 12 views
6

この質問は、thisスレッドのコメントのフォローアップです。関連のないロック文の後でread命令をロックの前に移動できますか?

// (1) 
lock (padlock) 
{ 
    // (2) 
} 
var value = nonVolatileField; // (3) 

さらに、のは(2)には命令がどのnonVolatileFieldへの影響およびその逆を持っていないと仮定してみましょう:

は、我々は次のコードを持っていると仮定しましょう。

読み込み命令(3)は、ロックステートメント(1)の前に終了するか、内部に(2)というように並べ替えることができますか?

C#仕様(§3.10)とCLI仕様(§I.12.6.5)の何もこのような並べ替えを禁止しています。

これはthisと同じ質問ではありませんのでご注意ください。ここでは、私が理解する限り、副作用とはみなされず、弱い保証があるため、読んだ指示について具体的に尋ねています。

答えて

3

私はそれはそれはあるかもしれないほど明確ではないのですが、これは部分的に、CLIの仕様によって保証されてを信じ。 I.12.6.5から:ロック(System.Threading.Monitor.Enterまたは同期メソッドを入力)を取得

は、暗黙的に揮発性の読み出し動作を行うものとし、ロック (System.Threading.Monitor.Exitまたは同期方法を残す)を放出することは、暗黙的に揮発性を行わなければなりません書き込み動作。 §12.6.7を参照のこと。 I.12.6.7から次に

読み取りがで読み出し命令の後に発生したメモリへの参照に先立って発生することが保証されていることを意味する「セマンティクスを取得」している揮発性の読み取りCIL命令シーケンス。揮発性書込みは、「解放セマンティクス」を有する。これは、書込みが、CIL命令シーケンスにおける書込み命令の前にメモリ参照の後に起こることが保証されることを意味する。

ロックを入力すると、(3)が(1)に移動しないようにする必要があります。 nonVolatileFieldからの読書はまだ「記憶への参照」としてカウントされていると私は信じている。しかし、ロックが終了すると、揮発性書き込みの前に読み込みが実行される可能性があるため、引き続き(2)に移動できます。

C#/ CLIのメモリモデルは、現時点ではたいへん望ましいものです。私は、すべてのことが大幅に明らかになることを望んでいる(そして、理論的には有効だが実際にはひどい最適化を無効にするために、おそらく強化されている)。

+0

こんにちはジョン、このコメントスレッドを乗っ取って申し訳ありませんが、これは私の質問には良い場所のようですが、C#6または7の仕様書がどこかにありますか?私はMads Torgersenがどこかで言及したことを知っています。彼はC#6のドラフトを持っていましたが、出版してはいけません。私は、誰かがそのような文書を知っていれば、それはあなただろうと思っています:) –

+0

@Damien_The_Unbeliever:そうです、編集します。 –

+0

@ LasseV.Karlsen:https://github.com/ljw1004/csharpspecにC#6仕様の草案がありますが、それはちょうど草案です。 ECMAのためのC#5仕様の標準化はまだ終わっていますが、これはECMAとMSの間で調和したいと思っているように、それ以降のバージョンではノックオン効果があります。 –

2

.NETに関する限り、モニター(lockステートメント)を入力すると、黙示的に揮発性の読み取りが行われ、モニターを終了すると(lockブロックの終わり)、リリースセマンティクスが得られます。暗黙的に揮発性の書き込みを行います(Common Language Infrastructure (CLI) Partition Iの§12.6.5ロックとスレッドを参照)。

volatile bool areWeThereYet = false; 

// In thread 1 
// Accesses, usually writes: create objects, initialize them 
areWeThereYet = true; 

// In thread 2 
if (areWeThereYet) 
{ 
    // Accesses, usually reads: use created and initialized objects 
} 

あなたはareWeThereYetに値を書き込むと、それが実行され、揮発性書き込みの後に並べ替えていなかったの前に、すべてのアクセスを。

areWeThereYetから読み取ると、その後のアクセスは揮発性読み取りの前に並べ替えられません。

この場合、スレッド2がareWeThereYetが変更されたことを確認すると、次のアクセス(通常は読み取り)が他のスレッドのアクセス(通常は書き込み)を監視することが保証されます。影響を受ける変数を混乱させる他のコードがないと仮定します。

SemaphoreSlimのような.NETの他の同期プリミティブについては、明示的には記述されていませんが、類似のセマンティクスを持たない場合はむしろ役に立たないでしょう。実際、それらに基づくプログラムは、メモリモデルの弱いプラットフォームやハードウェアアーキテクチャでも正しく動作しない可能性があります。


多くの人々は、Microsoftが現在のコードベース(Microsoft自身とそのクライアントのもの)は互換性を維持するためのx86/AMD64に似てこのようなアーキテクチャに、上の強力なメモリモデルを施行するべきであるという考えを共有しています。

私は、Microsoft WindowsでARMデバイスを持っていないように私ははるかに少ないARM用の.NET Frameworkで、自分自身を確認することはできませんが、アンドリューPardoe、CLR - .NET Development for ARM Processors、少なくとも1つのMSDNマガジンの記事は述べている:

CLRは、ECMA CLI仕様に必要なメモリモデルよりも強力なメモリモデルを公開することができます。たとえば、x86では、プロセッサのメモリモデルが強力であるため、CLRのメモリモデルは強力です。 .NETチームは、ARM上のメモリモデルをx86上のモデルほど強力にすることができましたが、可能な限り完全な順序付けを保証することは、コード実行パフォーマンスに顕著な影響を与えます。 ARMのメモリモデルを強化するための作業を行ってきました。具体的には、タイプセーフティを保証するためにマネージドヒープに書き込む際に重要なポイントにメモリバリアを挿入しましたが、これを最小限の影響で確実に行うようにしましたパフォーマンス。チームは専門家との複数の設計レビューを行い、ARM CLRに適用された技術が正しいことを確認しました。さらに、パフォーマンスベンチマークでは、x86、x64、およびARMで比較した場合、.NETコード実行パフォーマンスがネイティブC++コードと同じになることが示されています。

関連する問題