1

在我下面的代码中, 的Id属性ThreadClass未按预期确定性设置(ThreadArray[0]'s ThreadClass.Id = 0, ThreadArray[1]'s ThreadClass.Id = 1,等)。

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

主文件

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

线程类.cs

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被初始化为一个有效Thread对象。

4

2 回答 2

2

您使用的 C# 版本不会关闭i变量的新副本。到线程执行时,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

于 2012-08-13T20:31:45.897 回答
-1

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

——编辑达尼特在我之前得到了答案——:)

于 2012-08-13T20:29:17.507 回答