Mav*_*ick 5 c# multithreading captured-variable
我有以下代码创建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);
}
}
Run Code Online (Sandbox Code Playgroud)
我的理解是ParameterizedThreadStart将一个引用副本的对象发送到该线程.如果是这种情况,因为我没有i在每个循环中创建一个本地副本,所有新线程将指向相同的内存位置,这意味着某些线程号可能被"遗漏".虽然运行了这个(甚至对更多的线程/休眠时间),每个值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));
}
});
Run Code Online (Sandbox Code Playgroud)
这里的调用Start:
thread.Start(i);
Run Code Online (Sandbox Code Playgroud)
按值传递i(即复制其值),因为它是“值类型”并且不会在任何类型的匿名函数中捕获。从这个意义上说,它像任何普通struct方法一样传递给任何普通方法(因为这正是正在发生的事情)。
如果您将 lambda 编写为这样,而i不是使用threadNumber:
{
for (int j = 0; j < 10; j++)
{
Thread.Sleep(200);
Console.WriteLine(string.Format("Thread: {0}, Line: {1}", i, j));
}
});
Run Code Online (Sandbox Code Playgroud)
那你就有麻烦了。在这种情况下i,指的是原始变量位置,并且每当线程执行时都会对其进行求值。这意味着它可能是创建时的当前值i(不太可能只是由于处理时间),或者稍后在循环中设置的值for,或者最后一个可能的值10,并且很可能在迭代之间跳过或共享数字。