【问题标题】:Help understanding C# and multithreading帮助理解 C# 和多线程
【发布时间】:2011-02-12 18:08:38
【问题描述】:

嗨 我正在阅读“C# 中的线程”教程。它提到的一件事是:

“CLR 为每个线程分配自己的内存堆栈,以便局部变量保持独立”

还有这个例子:

namespace ConsoleApplication1 {
class Program {
    static void Main(string[] args) {
        for (int i = 0; i < 20; i++) {
            Thread t = new Thread(() => {
                Console.WriteLine(i);
            });
            t.Start();
        }
        Console.ReadLine();
    }
}

}

输出: 1 2 2 4 6 8 10 10 10 10 12 12 14 15 17 18 18 20 20

所以我理解这里发生的事情的方式是:

  • 主线程开始执行 for 循环。
  • 一个新线程被实例化和定义,这样它将接收“i”的值 并将其打印到控制台。
  • 线程实例在主线程继续工作的同时启动。

“i”是一个整数,我的猜测是新线程将在其内存堆栈中拥有自己的副本。然后将值打印到控制台。但正如结果显示的那样,它跳过了从 10 到 12 或 12 到 14 的值。 那么新线程是否正在接收对 i 的引用?但是如果“i”是一个整数,那么新线程不应该在它的内存堆栈中存储一个新值,而不是一个对 i 的引用。

还有为什么会有重复值?它打印了几次 2,10,12,18,20。

谢谢。

【问题讨论】:

  • 哪个教程?该示例是否与该文本直接相关?
  • 读了cmets后,发现作者确实提到了lamda表达式和共享变量的问题。我想我太专注于我认为它应该如何工作并且没有或不想意识到对于 lamda 表达式来说事情是不同的。感谢您的示例、回复和链接。 (这里是教程的链接:albahari.com/threading 部分 Lambda 表达式和捕获的变量)

标签: c# multithreading


【解决方案1】:

该示例存在致命缺陷...因为每个线程实际上共享一个 i 变量。它被 lambda 表达式捕获

这是一个非常常见的问题,但在线程教程中看到它真的很可惜。 (我希望这不是我的一篇文章!请告诉我们你在哪里读到这篇文章。)Eric Lippert 在他的博客文章中非常仔细地写过它,“关闭被认为有害的循环变量” - part 1; part 2.

值得区分线程行为和 lambda 表达式的行为。线程确实确实有自己的堆栈和自己的局部变量 - 但这里,i 由于 lambda 表达式而在所有线程之间共享。它不是“正常”意义上的局部变量。

这是一个示例,显示每个线程都有自己的局部变量:

using System;
using System.Threading;

public class Test
{
    static void Main()
    {
        for (int x = 0; x < 10; x++)
        {
            new Thread(Count).Start();
        }
    }

    static void Count()
    {
        int threadId = Thread.CurrentThread.ManagedThreadId;
        Console.WriteLine("Thread {0} starting", threadId);
        for (int i = 0; i < 5; i++)
        {
            Console.WriteLine("{0}: {1}", threadId, i);
        }
        Console.WriteLine("Thread {0} ending", threadId);
    }
}

每个线程肯定会打印 0..4 以及它自己的线程 ID。这次i 变量对每个线程来说都是真正的本地变量——没有共享。

【讨论】:

    【解决方案2】:

    当在 lambda 表达式中使用变量时,例如您的变量 i,它会被提升到 a 闭包中(在您的情况下是 Main 方法)(第一次在 google 上点击“closure c#”恰好是Jon Skeet's article on the subject)。正因为如此,它不是局部变量,也不存在于线程的堆栈中。

    【讨论】:

      【解决方案3】:

      问题很简单,因为胎面初始化和运行需要时间,同时 i 的值会发生变化。并且在其他线程获得处理器周期进行处理时,也有可能完成多个循环。因此,一个数字会被打印多次。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-29
        • 1970-01-01
        • 1970-01-01
        • 2011-03-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多