C# 并发将值类型传递给';Thread.Start';没有按预期工作

C# 并发将值类型传递给';Thread.Start';没有按预期工作,c#,.net,multithreading,C#,.net,Multithreading,在我下面的代码中,ThreadClass的Id属性未按预期进行确定设置(ThreadArray[0]的ThreadClass.Id=0,ThreadArray[1]的ThreadClass.Id=1,等) 如果我调试并减慢线程.Start()的,一切都会按预期工作。但是当程序以全速运行时,我会得到所有Id=4(或类似)。我无法锁定I,因为它不是引用变量。很明显,我遇到了一个比赛条件。我做错了什么 Main.cs for (int i = 0; i < ThreadCount; i++) {

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

如果我调试并减慢
线程.Start()的
,一切都会按预期工作。但是当程序以全速运行时,我会得到所有
Id=4
(或类似)。我无法锁定
I
,因为它不是引用变量。很明显,我遇到了一个比赛条件。我做错了什么

Main.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);
    }
}
预期输出:

我是线程0
我是线程1
我是线程2
我是线程3
... 5秒等待。。。
我是线程0
我是线程1
我是线程2
我是线程3
实际输出:

我是线程4
我是线程4
我是线程4
我是线程4
... 5秒等待。。。
我是线程4
我是线程4
我是线程4
我是线程4

请注意,此时,
ThreadArray
的每个实例都被初始化为有效的
Thread
对象。

将ThreadArray[i].Start()移动到for循环之外,只需在启动线程之前设置所有类即可。即使您必须循环两次,它也应该确保所有事情都按照您希望的顺序/状态发生


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

将您的ThreadArray[I].Start()移动到for循环之外,只需在启动线程之前设置所有类即可。即使您必须循环两次,它也应该确保所有事情都按照您希望的顺序/状态发生


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

您使用的是一个C版本,它不会覆盖
I
变量的新副本。执行线程时,
i
处于或接近
ThreadCount
。只需创建变量的一个副本,这样闭包就可以捕获:

for (int i = 0; i < ThreadCount; i++) 
{  
    int temp = i;
    ThreadArray[i] = new Thread(() =>  
        {              
            new ThreadClass(temp); 
        });      
}  
for(int i=0;i
{              
新螺纹等级(温度);
});      
}  

顺便说一下,VS 2012(或.NET 4.5)中的C#版本解决了这一问题。请参见

您正在使用的C#版本不会覆盖
i
变量的新副本。执行线程时,
i
处于或接近
ThreadCount
。只需创建变量的一个副本,这样闭包就可以捕获:

for (int i = 0; i < ThreadCount; i++) 
{  
    int temp = i;
    ThreadArray[i] = new Thread(() =>  
        {              
            new ThreadClass(temp); 
        });      
}  
for(int i=0;i
{              
新螺纹等级(温度);
});      
}  

顺便说一下,VS 2012(或.NET 4.5)中的C#版本解决了这一问题。请参见

See,以了解未来读者的详细信息,根据Rob的博客文章,.Net 4.5在我上面描述的情况下不会改变行为。此更改仅影响foreach()语句,如果希望lambda访问循环变量,则仍需要将循环变量复制到局部变量。有关详细信息,请参阅Rob的博客文章。在上述情况下,.Net 4.5不会更改行为。此更改仅影响foreach()语句,如果希望lambda访问循环变量,则仍需要将循环变量复制到局部变量。