我有以下代码创建10个线程,然后将消息写入控制台:
for (int i = 0; i < 10; i++)
{
{
Thread thread = new Thread((threadNumber) =>
{
for (int j = 0; j < 10; j++)
{
Thread.Sleep(200);
Console.WriteLine(string.Format("Thread: {0}, Line: {1}", threadNumber, j));
}
});
thread.Start(i);
}
}
我的理解是ParameterizedThreadStart
接受一个对象,该对象的引用副本被发送到该线程。如果是这种情况,因为我没有在每个循环中创建i
的本地副本,所有新线程将指向相同的内存位置,这意味着某些线程号可能被“遗漏”。虽然运行了这个(甚至针对更多的线程/休眠时间)i
的每个值都有自己的线程。任何人都可以解释原因吗?
答案 0 :(得分:4)
在创建将包裹i
的匿名函数的意义上,您尚未应用任何延迟或“已捕获”。
这里的lambda函数在任何地方都没有引用i
,它的状态完全内化/包含在这里没有问题:
(threadNumber) =>
{
for (int j = 0; j < 10; j++)
{
Thread.Sleep(200);
Console.WriteLine(string.Format("Thread: {0}, Line: {1}", threadNumber, j));
}
});
此处Start
致电:
thread.Start(i);
按值传递i
(即复制其值),因为它是“值类型”,并且不会在任何类型的匿名函数中捕获。从这个意义上讲,它会像任何正常的struct
一样传递给任何正常的方法(因为这正是发生的事情)。
相反,如果您使用i
代替threadNumber
编写了lambda:
{
for (int j = 0; j < 10; j++)
{
Thread.Sleep(200);
Console.WriteLine(string.Format("Thread: {0}, Line: {1}", i, j));
}
});
那你就麻烦了。在这种情况下,i
指的是原始变量位置,并将在线程执行时进行评估。这意味着可能是i
创建时的当前值(不太可能仅仅是由于处理时间),或稍后在for
循环中设置的值,或者最后一个可能的值10
,很可能在迭代之间跳过或共享数字。