2012-04-03 38 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到線程池
裝載:ITEM1 [THREAD:3]
ITEM1:是0% 完成[THREAD:3]
添加ITEM2到線程池
裝載:ITEM2 [THREAD:4]
ITEM2:是0%完成[THREAD:4]
ITEM1:是1%完成[THREAD:3]
ITEM2:是1%完成[THREAD:4]
ITEM1:是2%完成[THREAD: 3]
item2:是2%完成[THREAD:4]

但是,如果我刪除此行。

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

LoadItems方法,所述輸出如下所示。

添加ITEM1到線程池
添加ITEM2到線程池
裝載:ITEM2 [THREAD:4]
裝載:ITEM2 [THREAD:3]
ITEM2:是0%完成[THREAD:4]
ITEM2:是0%完成[THREAD:3]
ITEM2:是1%完成[THREAD:4]
ITEM2:是1%完成[THREAD:3]
ITEM2:是2%完成[THREAD:3 ]
i TEM2:是2%完成[線索:4]

問題

它好像正在使用兩個線程,但他們似乎都將作用於相同的數據。爲什麼代碼的行爲如此?

回答

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分鐘,根本無法看到它。 – 2012-04-03 12:09:05

+0

+1。至少必須有500個與這個問題相關的問題。到目前爲止我已經回答了一些。 – Aliostad 2012-04-03 12:12:10

3

有一點介意看代碼是缺乏使用的Interlocked的。

您必須使用it否則您會看到奇怪的錯誤和行爲。

所以不是

numThreads++; 

用途:

Interlocked.Increment(ref numThreads); 
+0

然後我會在'compCall'方法中調用'Interlocked.Decrement(ref numThreads)'嗎? – Tester101 2012-04-03 12:14:50

+0

@ Tester101當然是**包括遞減**。 – Aliostad 2012-04-03 12:17:40

相關問題