c# - 在 ParameterizedThreadStart 中捕获的变量

标签 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 的本地副本,所有新线程都将指向相同的内存位置,这意味着某些线程号可能会被“遗漏”。尽管运行了这个(甚至针对大量线程/ 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/

相关文章:

angular - 无法从 nativescript worker 访问 Angular 服务

c# - 帮助异常处理

c# - 在 Visual Studio Express 中开发 Silverlight?

java - 实例字段的线程安全

c# - 在 C# 中的循环中捕获变量

c# - 将两个正则表达式组合成一个键/值对对象?

c# - 捕获的变量... 'Captured' 实际上代表什么?

c# - 你知道 '@eax' 的托管等价物吗?

c# - 分层架构。正确地做

java - 匿名线程类的输出不同步