2012-12-20 128 views
0

我对c#和多线程有点新,所以我可能在这里犯了一个愚蠢的错误,但我似乎无法弄清楚这一点。我有一个应用程序根据在我的网络上发现的机器数量创建一个线程数组,然后为每台机器创建一个执行我创建的函数的线程。退出for循环后,我创建了另一个运行另一个函数的线程。我的函数工作得很好,没有问题,在退出for循环并继续创建下一个线程之后,问题出于某种原因,我的应用程序跳回到for循环,并且索引现在超出范围并导致抛出异常。我希望我明确地解释这一点,我很困惑,为什么发生这种情况,因为我不知道为什么当完成for循环时,它会执行一行代码并跳回去。反正这里是我的代码,任何帮助将不胜感激。c#多线程应用程序

 smThread = new Thread[networkedComputers.Count]; 

     for (UInt16 i = 0; i < networkedComputers.Count; i++) 
     { 
      smThread[i] = new Thread(delegate() { sm.RunServerMonitorPerMachine(networkedComputers[i].ToString()); }); 
      smThread[i].Start(); 
     } 

     dailyThread = new Thread(dailyEvents); 
     dailyThread.Start(); 
+0

我可能会检查出任务。我认为他们更直接一点。 http://msdn.microsoft.com/en-us/library/system.threading.tasks.task.aspx – MattW

+0

这不是一个答案,但总的来说,我认为在这里使用TPL会更好。通过管理低级细节本身,C#使得您比C++或C更容易。 http://msdn.microsoft.com/en-us/library/dd537609.aspx – Johnny

+1

你在另一个线程中触摸'networkedComputers'数组吗?当您在'for'循环中时'networkedComputer.Count'可能会改变。 –

回答

6

我认为你的问题就在这里:

networkedComputers[i].ToString() 
       ^

你可能期待的i值传递给线程,当你做到这一点,但实际上,你传递给i参考。这个引用随着循环而更新,所以当线程实际执行时,它很可能不会成为你期望的值。 (Google关键字:被捕获的变量)

解决方案是在将值传递给线程之前制作值的副本。此副本不会更新。

for (int i = 0; i < networkedComputers.Count; i++) 
{ 
    int tmp = i; 
    smThread[i] = new Thread(delegate() { sm.RunServerMonitorPerMachine(networkedComputers[tmp].ToString()); }); 
    smThread[i].Start(); 
} 
+0

+1为清楚的解释,但是不''我永远不会超过'networkedComputers.Count',因此它不应该导致'OutOfRangeException'?或者'''''''''for'''循环会检查它吗? –

+0

循环完成后,检查后'i'将保持超出范围。 –

+0

它可能因为超出范围而消失吗? –

1

Kendall Frey指出,捕获的循环变量问题很可能是您的问题。然而,正如你的文章中的其他评论者所说,这可能是研究C#的Task Parallelism Library的好例子,它可以为你处理很多这些事情。您的代码会是这个样子:

for (UInt16 i = 0; i < networkedComputers.Count; i++) { 
    int count = i; 
    Task.Factory.StartNew(() => sm.RunServerMonitorPerMachine(networkedComputers[count].ToString()); 
} 

Task.Factory.StartNew(() => dailyEvents()); 

这样做的好处是,你不必担心管理线程池的任务排队,并尽快拿起一个线程可以执行它们。另一件需要考虑的事情是,只有在for循环中的所有任务完成之后,才能执行您的dailyEvents任务,而不需要执行更多的工作。这是你在当前的解决方案中没有实现的东西(但是通过我认为你所要做的事情的外观);

+0

我看到一个捕获的变量! –

+0

我会给任务库一个尝试,我不能等到for循环中的函数完成,因为它是一个正在进行的过程,我用它来记录perfmon数据,因此,除非我停止运行服务。 – mgrenier

+0

@KendallFrey雅我给你信用指出他的原始实现的错误只是想表明TPL是一个很好的方式来处理这样的线程问题在C# –