2016-05-19 5 views
-1

はここマルチスレッド環境でクラスインスタンスの値が壊れているのはなぜですか?

class Program 
{ 
    static void Main(string[] args) 
    { 
     for (int i = 0; i < 100; i++) 
     { 
      Thread thread = new Thread(new ThreadStart(()=> SimpleClass.Instance.weird.SetHello(i))); 
      thread.Start(); 
     } 

     Console.Read(); 
    } 
} 

interface IClass 
{ 
    WeirdClass weird{ get; set; } 
} 

class SimpleClass : IClass { 
    public static SimpleClass Instance = new SimpleClass(); 

    public WeirdClass weird{ get; set; } 

    public SimpleClass() 
    { 
     weird= new WeirdClass(); 
    } 
} 

class WeirdClass 
{ 
    public int hello; 

    public void SetHello(int i) 
    { 
     this.hello = i; 
     Console.WriteLine(this.hello); 
    } 
} 

我々はWeirdClassの「ハロー」の値がマルチスレッドで正しく行われていません見ることができ、値は単に静的インスタンスのようですが、そうではありません、単純なコードです。

おそらく、魔法はSimpleClass.Instance.asyncで起こるかもしれません。ありがとう

+1

[ask]と明示してください。それはどのように「腐敗していますか?あなたは1つの 'WeirdClass'インスタンスで作業していることを認識していますか? – CodeCaster

+2

コンテキストキーワードであるので、識別子として 'async'を使用することについて強くお勧めします。 –

+2

とにかく[クロージャへのアクセス(2)](http ://stackoverflow.com/questions/304258/access-to-modified-closure-2)。 – CodeCaster

答えて

0

私はいくつかの興味深い研究に私をもたらしたので、私はあなたの質問をupvoted。 (例えば、入れ

var ii = i; 
Thread thread = new Thread(
    new ThreadStart(()=> SimpleClass.Instance.async.SetHello(ii))); 
thread.Start(); 

私は異なる構成と異なるコンテキストでそれをテストしてみた:ループのために一時iii変数を割り当てるとスレッドの初期化にiiを使用し、このように

helloの割り当てとConsole.WriteLineの間のランダムThread.Sleep)。

私の解決方法はこれです:すべてのスレッドは独自のiを持っており、Consoleに一度だけ書き込まれます。 を作成すると、スレッドが順番に開始されないため、数字は順番に書き込まれません。

ジャストサイドノート:@JonSkeetが推奨されているように、識別子としてasync使用していない、それは予約語です。使用する代わりにAsyncWeirdInnerClassHelloContainer、または何でもそれは、公式のC#のトークンではありませんそれ以外の場合は、あなたのコードはあまり明らかになりました。

UPDATE - 解決

これ:

for(int i = 0; i < 10; i++) 

これに相当する:

int i; 
for(i = 0; i < 10; i++) 

両方の場合においてiforループの外部で作成された、であること、およびループの異なるサイクル間で何らかの形で共有されます。あなたが提供するリンク@CodeCasterをチェックすると、あなたは、C#の以前のバージョンとforeachループで同じ問題が表示されます。あなたが入力としてiでサイクルでスレッドを宣言すると

、あなたがスレッドに言っている:は「OK、あなたが起動したとき、i値を取得します!」。その瞬間、iは、適切な値を持っていますが、スレッドは、それが効果的に開始した唯一のiを要求し、その値が既にメインスレッドが既にループの新しいサイクルを開始しましたし、既に再割り当てしているので、その間に変更されました次の反復のためi

ループ内にの中に一時変数を作成すると、そのサイクルに残り、外部には見えません。

これは、ゲーム全体のデモンストレーションです:ループの外iiを宣言しようとする...行動は、あなたがi変数を示したことが、再び間違ったものです。

+0

はい、あなたのコードは正しい結果を返します....違いは何ですか... – liuzhidong

+0

あなたは[このブログの記事]を読む必要があります(https://blogs.msdn.microsoft.com/ericlippert/2009/11)。/12/closed-over-the-loop-variable-considered-harmful /)を使用して、有用で正しい答えを投稿したい場合に使用します。 –

+0

@ MK87:この動作は、新しいバージョンのC#コンパイラで変更されました。それは、プロジェクトのビルドに使用された.NETコンパイラのバージョンによって決まります。ランタイム互換性の問題ではありません。 –

関連する問題