0

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

        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();
4

2 回答 2

6

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

networkedComputers[i].ToString()
                   ^

执行此操作时,您可能希望将 的值传递i给线程,但实际上,您传递了对 . 的引用i。此引用会在您循环时更新,因此当线程实际执行时,它很可能不是您期望的值。(谷歌关键字:捕获的变量)

解决方案是在将值传递到线程之前对其进行复制。此副本不会更新。

for (int i = 0; i < networkedComputers.Count; i++)
{
    int tmp = i;
    smThread[i] = new Thread(delegate() { sm.RunServerMonitorPerMachine(networkedComputers[tmp].ToString()); });
    smThread[i].Start();
}
于 2012-12-20T13:50:26.960 回答
1

正如 Kendall Frey 指出的那样,捕获的循环变量的问题很可能是您的问题。但是,正如您帖子中的其他一些评论者所建议的那样,这可能是研究 C#s 任务并行库的一个很好的案例,它为您处理了很多这些事情。您的代码将如下所示:

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 任务不会执行更多工作。这是您在当前解决方案中没有实现的东西(但从外观上看,我认为它是您想要的);

于 2012-12-20T14:04:28.587 回答