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访问循环变量,则仍需要将循环变量复制到局部变量。