2015-12-16 12 views
7

複数のスレッドを起動すると、解析中のパラメータidが間違っていることがあります。ここに私のスタートアップは、次のとおりです。スレッドパラメータが変更されています

for (int i = 0; i < _threadCount; i++) 
{ 
    Thread thread = new Thread(() => WorkerThread(i)); 
    thread.Start(); 
    _threads.Add(thread); 
} 

そして、私のスレッド関数:

private void WorkerThread(int id) 
{ 
    Console.WriteLine("[{0}] Thread started {1}", DateTime.Now.ToLongTimeString(), id); 
} 

このコードの出力は次のとおりです。

私の心には、このコードが持つすべてのスレッドを作成する必要があります
[19:10:54] Thread start 3 
[19:10:54] Thread start 9 
[19:10:54] Thread start 4 
[19:10:54] Thread start 12 
[19:10:54] Thread start 11 
[19:10:54] Thread start 3 
[19:10:54] Thread start 12 
[19:10:54] Thread start 6 
[19:10:54] Thread start 9 
[19:10:54] Thread start 6 
[19:10:54] Thread start 13 
[19:10:54] Thread start 2 
[19:10:54] Thread start 15 
[19:10:54] Thread start 9 
[19:10:54] Thread start 15 

上記のように重複ではなくユニークなidです。

コンパイラ情報:

プラットフォームターゲット:x64の

ターゲットフレームワーク:.NET Frameworkの4.5

+2

すべてのスレッドが同じ変数を共有しています。 – SLaks

+0

誰かが実際に似たような質問を投稿しましたが、ここではその件に関するエリック・リッペルトのリンク記事があります。面白いです。http://ericlippert.com/2009/11/12/closing-over-the-loop-variable-considered-harmful-part-one/ – KDecker

答えて

9

あなたは、誤ってスレッドを開始した後iのように撮影した変数の変更について注意する必要がありますので、 i共有です。 i変数は、ループの存続期間全体にわたって同じメモリ位置を参照します。 ソリューションは、このような一時変数を使用することです:

for (int i = 0; i < _threadCount; i++) 
{ 
     var i1 = i; 
     Thread thread = new Thread(() => WorkerThread(i1)); 
     thread.Start(); 
     _threads.Add(thread); 
} 

読むよりおよそクロージャここ:The Beauty of Closures from (Jon Skeet)Lambda expressions and captured variables from (Joseph Albahari).

+0

面白いです。私は引数として値型を渡すと自動的にそれを行うと思っていたでしょう。関数呼び出しと、WorkerThreadの引数リストにコピーされる前に変更できる最初の行が実行されるときに、ある程度の移行期間がありますか? – Jakotheshadows

+0

ありがとうございました。そして、ええ@Jakotheshadows私は同じと仮定した – JonasMH

+0

私はそれが今私にとって意味をなさないと思う。 thread.Start();を実行しても、WorkerThreadの関数呼び出しは必ずしも発生しません。それはループ中のいつでも発生する可能性があり、WorkerThreadが他のスレッド(おそらくスレッドがインスタンス化された場所の5回前の繰り返し)で呼び出され、評価されて引数リストにコピーされるときだけです。ここでの問題は、実際にスレッドが始まるまで評価されていないことです。 – Jakotheshadows

0

問題はi変数が同じメモリ位置を指していることですループの寿命を通して。したがって、各スレッドは、実行中に値が変化する可能性のある変数を呼び出します。解決策は、ユーザに一時変数int temp = iを渡すことです。 @ S.Akbariは言った。

+1

最初の 'volatile'は、ローカルではなくクラスまたは構造体フィールドにのみ適用できます。第2に、以前に作成されたスレッドが実行される前に、キャプチャされた変数がインクリメントされる可能性があるという事実は変わりません。 – juharr

関連する問題