在使用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);