2010-09-29 30 views
0

我在测试一个简单的线程池解决方案之前,我把它放入我的应用程序,但我看到的结果对我来说没有意义。我有一个简单的表单,只有一个按钮。此按钮启动以下循环:ThreadPool参数

private void button1_Click(object sender, EventArgs e) 
{ 
    MyTestThread oTask = new MyTestThread(); 
    MyThreadInfo oTaskParameters = new MyThreadInfo(); 
    for (int i = 1; i <= 5; i++) 
    { 
     objTaskParameters.MyGuid = Guid.NewGuid(); 
     objTaskParameters.MyNumber = i; 
     ThreadPool.QueueUserWorkItem(new WaitCallback(objTask.ProcessDataForNTime), objTaskParameters); 
    } 
    Console.WriteLine("All threads have been queued for processing..."); 
} 

它调用的类看起来像这样。它有一个参数MyThreadInfo类,然后MyTestThread类只需循环10秒钟即可完成。

public class MyThreadInfo 
{ 
    public int MyNumber; 
} 

public class MyTestThread 
{ 
    public void ProcessDataForNTime(Object oParameters) 
    { 
     //We pass parameters 
     MyThreadInfo oThread = (MyThreadInfo)oParameters; 
     int threadNo = oThread.MyNumber; 

     Console.WriteLine("thread {0} started...", threadNo); 

     int iN = 10; //Delay for 10 seconds 
     DateTime dteStart = DateTime.Now; 
     do 
     { 
      System.Threading.Thread.Sleep(1000); //Wait a second before we look again 
     } while (dteStart.AddSeconds(iN) > DateTime.Now); 

     Console.WriteLine("thread {0} completed...", threadNo); 
    } 
} 

我期待这个结果在控制台/输出/调试日志中显示。当我通过应用程序步骤,我其实看到这一点:

thread 1 started... 
thread 2 started... 
thread 3 started... 
thread 4 started... 
thread 5 started... 
All threads have been queued for processing... 
thread 1 completed... 
thread 2 completed... 
thread 3 completed... 
thread 4 completed... 
thread 5 completed... 

,但如果我全速运行的应用程序,而无需通过代码或断点步进,它输出这样的:

All threads have been queued for processing... 
thread 5 started... 
thread 5 started... 
thread 5 started... 
thread 5 started... 
thread 5 started... 
thread 5 completed... 
thread 5 completed... 
thread 5 completed... 
thread 5 completed... 
thread 5 completed... 

通过使代码正常工作的代码是什么?我确实注意到向循环中添加Thread.Sleep(1000)(1秒)确实会强制应用程序正确标记线程,但我正在尝试开发一个快速多线程应用程序,并添加1秒延迟每个线程都令人沮丧。

有人可以给我一些见解,为什么我看到这种行为?

感谢...

山姆

回答

6

您需要将每一个新的线程一个全新的对象。目前,他们都得到制作MyNumber可设置为PARAM上MyThreadInfo构造后的引用在主线程中的同一个对象,即oTaskParameters

试试这个,:

for (int i = 1; i <= 5; i++) 
{ 
    MyThreadInfo oTaskParameters = new MyThreadInfo(i); 
    objTaskParameters.MyGuid = Guid.NewGuid(); 
    ThreadPool.QueueUserWorkItem(new WaitCallback(objTask.ProcessDataForNTime), objTaskParameters); 
} 

MyThreadInfo(int i) : MyNumber(i) 
{ 
    // rest of construction logic 
} 

这一变化意味着,每一个新的线程得到MyThreadInfo的一个不相交的实例,该线程的ID适当地设置。

仍然不能保证线程将按升序打印出它们的ID。您必须引入某种类型的FIFO队列/处理来执行该操作。有关于该问题ordering of thread execution using Threadpool.QueueUserWorkItem的详细讨论。

+0

完美。我并不担心订单,只是能够在发生时识别这些线索。谢谢你的帮助! – Sam 2010-09-29 13:38:43

+0

@Sam - 很高兴这有帮助 – 2010-09-29 13:39:45