5

は、いくつかの方法で、このC#コードを想像してみて:コレクション初期化子を使用すると、別のスレッドが部分的に作成したコレクションを参照できますか?

SomeClass.SomeGlobalStaticDictionary = new Dictionary<int, string>() 
{ 
    {0, "value"}, 
}; 

はのは、誰も明示的なメモリバリアを使用していないか、辞書にアクセスするためにロックしているとしましょう。

最適化が行われない場合、グローバル辞書はnull(初期値)または1つのエントリを持つ適切に構成された辞書である必要があります。

質問ですが:(?またはその他の無効な部分的に構築された辞書)の追加コールの効果とSomeGlobalStaticDictionaryへの割り当ては、いくつかの他のスレッドが空のnull以外SomeGlobalStaticDictionaryを見ることになるよう並べ替えることができます

がしますSomeGlobalStaticDictionaryがvolatileであれば答えを返しますか?

http://msdn.microsoft.com/en-us/magazine/jj863136.aspx(およびその2番目の部分)を読んだ後、理論的には1つの変数がソースコードに割り当てられているという理由だけで、他のスレッドはさまざまな理由でそれを別々に見るかもしれません。 ILコードを調べましたが、問題は、SomGlobalStaticDictionaryの割り当ての前に、JITコンパイラおよび/またはCPUがAdd呼び出しの効果を他のスレッドに "フラッシュ"できないかどうかです。ローカル変数で

+0

私は、両方の質問の答えが複数のスレッドの存在下ではイエスだと思うが、メモリモデルを十分理解しているとは思えない。 – SLaks

+0

http://www.amazon.com/CLR-via-Microsoft-Developer-Reference/dp/0735667454 – SLaks

+1

このコードは法的ではありません。そこに 'var'を入れてもよろしいですか?地方自治体は揮発性ではなく、名前にドットが含まれません。あなたはそれをフィールドにしようとしていますか? –

答えて

4

私はあなたの質問への答えを知っていないと言ってみましょうが、私はあなたがその本質にそれを簡素化することができます

unsafe class C 
{ 
    static int x; // Assumed to be initialized to zero 
    static int *p; // Assumed to be initialized to null 
    static void M() 
    { 
     int* t = &C.x; 
     *t = 1; 
     C.p = t; 
    } 
    ... 

ここint辞書用で立っている、pがあります辞書を参照しているフィールドには、tが一時的に作成され、辞書に要素を追加することは、フィールドxの値を変更してモデル化されます。したがって、ここでの一連のイベントは、辞書の格納場所を取得して一時的に保存し、次に参照したものを変更してから結果をパブリッシュします。

質問は、C#メモリモデルの下で、別のスレッドのオブザーバがxを指しており、xがまだゼロであることを見ることが許可されているかどうかです。

私が言ったように、私は確かにその答えを知らない。私は調べることに興味があるだろう。

なぜ私の頭の上から外れているのですか:なぜそれはではなく、が可能でしょうか? pxは完全に異なるメモリページに置くことができます。あるプロセッサ上でxの値がプリフェッチされているが、pの値がプリフェッチされていないとします。そのプロセッサはpがヌルではなく、xがまだゼロであることを観察できますか?それを止めるのは何ですか?

+0

ありがとうございます。はい、それは質問の本質です。しかし、私はコレクションのイニシャライザのための答えを具体的に言いたいと思います。つまり、C#または.NET仕様でコレクションのイニシャライザ用にメモリバリアを生成する必要があるとすれば、2つの答えが異なるかもしれません(現在、私はそれがないと仮定します)。したがって、生成されたILコードを十分に(例えばildasmを介して)調べているか、またはJITコンパイラが「コレクションイニシャライザのためだけに」異なるルールを適用できるかどうかです。 – Palo

+0

@Palo:JITはコレクション初期化子について何も知らず、C#spceはコレクション初期化子固有の保証を行いません。 –

+0

@Palo:C#仕様では、スレッド間を行き来するものの可視性について唯一の保証は、揮発性フィールドの書き込みやロックの取り出しやスレッドの開始などの特別な副作用についてです。コレクションのイニシャライザはその中に入っていません。 –

6

最適化がオンで、コンパイラは、(少なくとも時々)を(オブジェクト初期化子のために、またはプロパティを設定する)Addを呼び出し、最初の変数に割り当てるコードにコンパイルされます。

あなたは、静的またはインスタンス変数を使用する場合は、異なる動作が表示されます:

class Test 
{ 
    static List<int> StaticList = new List<int> { 1 }; 
    List<int> InstanceList = new List<int> { 2 }; 
} 

は、次のタイプ初期化子のILを与える:

.method private hidebysig specialname rtspecialname static 
     void .cctor() cil managed 
{ 
    // Code size  21 (0x15) 
    .maxstack 2 
    .locals init (class [mscorlib]System.Collections.Generic.List`1<int32> V_0) 
    IL_0000: newobj  instance void class [mscorlib]System.Collections.Generic.List`1<int32>::.ctor() 
    IL_0005: stloc.0 
    IL_0006: ldloc.0 
    IL_0007: ldc.i4.1 
    IL_0008: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0) 
    IL_000d: nop 
    IL_000e: ldloc.0 
    IL_000f: stsfld  class [mscorlib]System.Collections.Generic.List`1<int32> Test::StaticList 
    IL_0014: ret 
} // end of method Test::.cctor 

そして、次のコンストラクタのIL:

.method public hidebysig specialname rtspecialname 
     instance void .ctor() cil managed 
{ 
    // Code size  29 (0x1d) 
    .maxstack 3 
    .locals init (class [mscorlib]System.Collections.Generic.List`1<int32> V_0) 
    IL_0000: ldarg.0 
    IL_0001: newobj  instance void class [mscorlib]System.Collections.Generic.List`1<int32>::.ctor() 
    IL_0006: stloc.0 
    IL_0007: ldloc.0 
    IL_0008: ldc.i4.2 
    IL_0009: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0) 
    IL_000e: nop 
    IL_000f: ldloc.0 
    IL_0010: stfld  class [mscorlib]System.Collections.Generic.List`1<int32> Test::InstanceList 
    IL_0015: ldarg.0 
    IL_0016: call  instance void [mscorlib]System.Object::.ctor() 
    IL_001b: nop 
    IL_001c: ret 
} // end of method Test::.ctor 

どちらの場合でも、コレクションには前にが設定されていますフィールドが設定されています。今ではメモリモデルの問題はまだないかもしれないが、ではなくというフィールドは、空のコレクションを参照するように設定されているフィールドと同じで、Addコールが行われていると同じです。割り当てスレッドの観点から、割り当てはAddの後に行われます。前にあなたが割り当てにそれを使用する場合には、プロパティのセッターがすべてと呼ばれているように、割り当てが行われる - 一般的には、オブジェクト初期化子とコレクションの両方の初期化子式は一時的な変数を使用してオブジェクトを構築するための等価です

オブジェクト/コレクションイニシャライザの他のスレッドの可視性については、特別な保証が与えられています。私はあなたが、仕様に従って「長距離」と書かれた場合にコードがどのように見えるかを想像し、そこから理由を推測することをお勧めします。

です。静的イニシャライザとコンストラクタには保証がありますが、主にMicrosoftの「一般」保証(例:C#仕様またはECMA仕様内)。

+0

'SomeClass.SomeGlobalStaticDictionary';彼は静的なフィールドについて質問しようとしています。そして、私が理解するように、彼は具体的にはメモリの並べ替えについて質問しています。 – SLaks

+0

@SLaks:それから、 'var'部分は誤解を招き始めます。私はOPが少し混乱していると思っていますが、私は明確にします。 –

+0

そうかもしれませんが、彼はすぐに書いていて、 'var'については考えなかったと思います。彼はメモリモデルが何であるかを理解しているように思います。 – SLaks