2012-04-03 2 views
4

コード

using System; 
using System.Threading; 

public delegate void LoadingProgressCallback(double PercentComplete,string ItemName); 
public delegate void LoadCompleteCallback(int ItemID, string ItemName); 

public static class Program 
{ 
    public static void Main(string[] args) 
    { 
     LoadTest loadTest = new LoadTest(); 
     loadTest.LoadItems(args); 
    } 
} 

public class LoadTest 
{  
    ManualResetEvent resetEvent; 
    int numThreads = 0; 

    public LoadTest() 
    {} 

    public void LoadItems(string[] Items) 
    { 
     numThreads = 0; 
     resetEvent = new ManualResetEvent(false); 

     foreach(string item in Items) 
     { 
      Console.WriteLine("Adding {0} to ThreadPool",item); 
      ThreadPool.QueueUserWorkItem 
      (
       delegate 
       { 
        Load(item, this.progCall, this.compCall); 
       } 
      ); 
      numThreads++; 

      Thread.Sleep(100);//Remove this line 

     } 
     resetEvent.WaitOne(); 
    } 

    public void progCall(double PercentComplete, string ItemName) 
    { 
     Console.WriteLine("{0}: is {1}% Complete [THREAD:{2}]",ItemName,PercentComplete.ToString(),Thread.CurrentThread.ManagedThreadId.ToString()); 
    } 
    public void compCall(int ItemID, string ItemName) 
    { 
     Console.WriteLine("{0}: is Complete",ItemName); 
     numThreads--; 
     if(numThreads == 0) 
     { 
      resetEvent.Set(); 
     } 
    } 

    public void Load(string Item, LoadingProgressCallback progressCallback, LoadCompleteCallback completeCallback) 
    { 
     Console.WriteLine("Loading: {0} [THREAD:{1}]",Item,Thread.CurrentThread.ManagedThreadId.ToString()); 

     for(int i = 0; i <= 100; i++) 
     { 
      if(progressCallback != null) 
      { 
       progressCallback((double)i, Item); 
      } 
      Thread.Sleep(100); 
     } 
     if(completeCallback != null) 
     { 
      completeCallback(0,Item); 
     } 
    } 
} 

観察

私はThreadPoolを使って作業するとき、誰かがこの奇妙な動作を説明できますか?

>TheProgram item1 item2

...このように、コマンドラインからこのプログラムを実行すると、出力は次のようになります。 ITEM1 [スレッド:3]
ITEM1:0% 完全[スレッド:3]である:ITEM2 [スレッド:4]
ThreadPoolの
読み込みにITEM2追加 ThreadPoolの
に読み込んITEM1追加


ITEM2:0%完了[スレッド:4]である
ITEM1:1%完了[スレッド:3]は
ITEM2する:1%完了[スレッド:4]である
ITEM1:2%完全[スレッドです。 3]
item2:2%完了[THREAD:4]

ただし、この行を削除した場合。 LoadItems方法から

Thread.Sleep(100);//Remove this line

、出力は次のようになります。 ITEM2 [スレッド:4]
読み込ん:ITEM2 [スレッド:3]
ITEM2:0%完了[スレッド:4]である
ThreadPoolの
読み込みにITEM2追加のThreadPool
にITEM1追加

ITEM2:0%完了[スレッド:3]は
ITEM2:1%完了[スレッド:4]である
ITEM2:1%完了[スレッド:3]は
ITEM2:2%完了[スレッド:3 ]
i tem2:2%コンプリート[スレッド:4]は、どちらも同じデータに作用しているように見えるものの

が質問

これは、2つのスレッドが使用されているかのように思えます。なぜコードはこのように動作しますか?

答えて

8

あなたはあなたに予期しない結果が得られるループ変数、上で閉じています。代わりにこれを試してみてください。すぐにコードを見て頭に浮かぶ

foreach(string item in Items) 
{ 
    string item2 = item; 
    Console.WriteLine("Adding {0} to ThreadPool", item2); 
    ThreadPool.QueueUserWorkItem 
    (
     delegate 
     { 
      Load(item2, this.progCall, this.compCall); 
     } 
    ); 
    numThreads++; 

    Thread.Sleep(100);//Remove this line 

} 

参照

+0

+1グッドキャッチは、私は5分間のコードを見つめて、単にそれを見ていません。 –

+0

+1。この問題だけに関連して少なくとも500の質問が必要です。私はこれまでにいくつか答えました。 – Aliostad

3

ことの一つは、Interlockedの使用の欠如です。

あなたはそうあなたが奇妙なエラーや行動が表示されますitを使用する必要があります。

ので、代わりの

numThreads++; 

用途:

Interlocked.Increment(ref numThreads); 
+0

'compCall'メソッドで' Interlocked.Decrement(ref numThreads) 'を呼び出すでしょうか? – Tester101

+0

@Tester101はいもちろんです**デクリメント**を含みます。 – Aliostad