在我的代码下面,ThreadClass
的Id
属性未按预期确定性设置(ThreadArray[0]'s ThreadClass.Id = 0, ThreadArray[1]'s ThreadClass.Id = 1,
等)。并发传递值类型为'Thread.Start'不能按预期方式工作
如果我调试并放慢了Thread.Start()'s
,一切都按预期工作。但是当程序全速运行时,我得到所有Id's = 4
(或类似的)。我无法锁定i
,因为它不是参考变量。显然,我遇到了一个竞争条件。我究竟做错了什么?
Main.cs
for (int i = 0; i < ThreadCount; i++)
{
ThreadArray[i] = new Thread(() =>
{
new ThreadClass(i);
});
ThreadArray[i].Start();
}
ThreadClass.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
对象。
有关详细信息,请参阅http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx – 2012-08-13 20:33:00
对于未来的读者,基于Rob的博客文章,.Net 4.5不会改变上述情况下的行为。这个改变只影响foreach()语句,如果你希望lambda访问一个循环变量,你仍然需要将循环变量复制到一个局部变量。 – 2012-08-13 20:55:32