我有以下代码创建 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
的本地副本,所有新线程都将指向相同的内存位置,这意味着某些线程号可能会被“遗漏”。尽管运行了这个(甚至针对大量线程/ sleep 时间),i
的每个值都有自己的线程。谁能解释一下为什么?
最佳答案
在创建将包装 i
的匿名函数的意义上,您没有应用任何延迟 或“捕获”。
这里的 lambda 函数没有在任何地方引用 i
,它的状态是完全内部化/包含的,所以这里没有问题:
(threadNumber) =>
{
for (int j = 0; j < 10; j++)
{
Thread.Sleep(200);
Console.WriteLine(string.Format("Thread: {0}, Line: {1}", threadNumber, j));
}
});
此处的开始
调用:
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
,并且很可能在迭代之间跳过或共享数字。
关于c# - 在 ParameterizedThreadStart 中捕获的变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17632627/