在ParameterizedThreadStart中捕获变量

时间:2013-07-13 17:39:32

标签: 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);
    }
}

我的理解是ParameterizedThreadStart接受一个对象,该对象的引用副本被发送到该线程。如果是这种情况,因为我没有在每个循环中创建i的本地副本,所有新线程将指向相同的内存位置,这意味着某些线程号可能被“遗漏”。虽然运行了这个(甚至针对更多的线程/休眠时间)i的每个值都有自己的线程。任何人都可以解释原因吗?

1 个答案:

答案 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,很可能在迭代之间跳过或共享数字。