在使用ThreadPool时,有人可以解释这种奇怪的行为吗?

代码

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); } } } 

意见

如果我从命令行运行这个程序,就像这样……

>TheProgram item1 item2

输出将如下所示。

将item1添加到ThreadPool
正在加载:item1 [THREAD:3]
item1:0%完成[THREAD:3]
将item2添加到ThreadPool
正在加载:item2 [THREAD:4]
item2:0%完成[THREAD:4]
item1:完成1%[THREAD:3]
第2项:完成1%[线程数:4]
第1项:完成2%[线程数:3]
第2项:完成2%[线程数:4]

但是,如果我删除此行。

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

LoadItems方法,输出看起来像这样。

将item1添加到ThreadPool
将item2添加到ThreadPool
正在加载:item2 [THREAD:4]
正在加载:item2 [THREAD:3]
item2:0%完成[THREAD:4]
item2:0%完成[THREAD:3]
第2项:完成1%[线程数:4]
第2项:完成1%[线程数:3]
第2项:完成2%[线程数:3]
第2项:完成2%[线程数:4]

问题

似乎两个线程正在被使用,尽管它们似乎都在使用相同的数据。 为什么代码表现如此?

您正在关闭循环变量,这会给您带来意想不到的结果。 试试这个:

 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 } 

参考

  • 在C#中关闭循环变量
  • 关闭循环变量被认为是有害的

立即想到看代码的一件事是没有使用Interlocked

你必须使用它,否则你会看到奇怪的错误和行为。

而不是

 numThreads++; 

使用:

 Interlocked.Increment(ref numThreads);