5

如何同时运行一些线程而不会“运行两次”或“失败”其中一个?我将用一个例子来解释我的问题:

private int count = 0;
private HashSet<int> hs_pages = new HashSet<int>();

for (int page = 1; page <= 10; page++)
{
    Thread thread = new Thread(unused => my_method(page));
    thread.Name = "Thread - " + page.ToString();
    thread.Start();
}
while(count < 10)
{

}

my_method()实现为:

public void my_method(int page)
{
    if (hs_pages.Add(page))
    {    
           count++;
          //My Codes
    }
    else
    {
          MessageBox.Show("this is duplicate of page : " + page.ToString());
    }
}

运行此代码后,我发现有些页面(1-10)没有运行,有些页面运行了两次。
所以while()永远不会因为那些重复和失败而结束。

我怎样才能修复那些重复和失败?

我的失败的意思不是“错误”,我的意思是例如my_method(4)从不运行,我的重复的意思是例如my_method(3)运行两次。

我知道还有其他方法,例如Parallel.ForEach,但我想学习如何使用 Thread 类。

4

1 回答 1

7

您正在关闭循环变量。

闭包关闭变量而不是。您正在创建的 lambda 不会在循环体内获取当前值的副本,它正在创建对该变量的引用,并且当匿名方法在某个时间点实际执行page时,它将访问该变量的值未来。到执行实际发生时,循环已经继续并增加了该值若干次(我们不知道有多少;这将取决于线程的调度方式)。

将其复制page到循环体的本地,以便每个闭包都位于不同的变量上,而不是正在变异的单个变量:

for (int page = 1; page <= 10; page++)
{
    int pageCopy = page;
    Thread thread = new Thread(unused => my_method(pageCopy , count));
    thread.Name = "Thread - " + pageCopy.ToString();
    thread.Start();
}

此外,您不应该忙着等待所有线程完成;花费大量 CPU 时间在 while 循环中无所事事地旋转是非常浪费系统资源的。而是在创建它们时Thread将您创建的所有对象放入 a 中List<Thread>,然后在完成后再次遍历列表并调用Join它们以等待它们完成。

于 2013-10-11T19:22:54.430 回答