将值类型传递给'Thread.Start'的并发不能按预期工作

时间:2012-08-13 20:24:33

标签: c# .net multithreading

在我的下面的代码中,Id的{​​{1}}属性未按预期确定(ThreadClass等)。

如果我调试并减慢ThreadArray[0]'s ThreadClass.Id = 0, ThreadArray[1]'s ThreadClass.Id = 1,的速度,一切都按预期工作。但是当程序以全速运行时,我得到所有Thread.Start()'s(或类似的)。我无法锁定Id's = 4,因为它不是引用变量。显然,我遇到了竞争条件。我做错了什么?

Main.cs

i

ThreadClass.cs

for (int i = 0; i < ThreadCount; i++)
{
    ThreadArray[i] = new Thread(() =>
        {
            new ThreadClass(i);
        });
    ThreadArray[i].Start();
}

预期输出:

private int Id { get; set; }

public ThreadClass(int i) {
    Id = id;
    while(true)
    {
        Console.WriteLine("I am thread " + i");
        Thread.Sleep(5000);
    }
}

实际输出:

I am thread 0
I am thread 1
I am thread 2
I am thread 3
... 5 second wait ...
I am thread 0
I am thread 1
I am thread 2
I am thread 3

请注意,此时I am thread 4 I am thread 4 I am thread 4 I am thread 4 ... 5 second wait ... I am thread 4 I am thread 4 I am thread 4 I am thread 4 的每个实例都会初始化为有效的ThreadArray对象。

2 个答案:

答案 0 :(得分:2)

您使用的是不会关闭i变量的新副本的C#版本。在执行线程时,i处于或接近ThreadCount。只需创建变量的副本,以便闭包可以捕获它:

for (int i = 0; i < ThreadCount; i++) 
{  
    int temp = i;
    ThreadArray[i] = new Thread(() =>  
        {              
            new ThreadClass(temp); 
        });      
}  

顺便说一句,VS 2012(或.NET 4.5)中的C#版本修复了这个问题。见http://msdn.microsoft.com/en-us/library/hh678682(v=vs.110).aspx

答案 1 :(得分:-1)

将你的ThreadArray [i] .Start()移到for循环之外,然后在启动线程之前简单地设置所有类。即使你必须循环两次,它应该确保一切都按照你想要的顺序/状态发生。

- 编辑Darnit在我做之前得到了答案 - :)