关于在Thread中传递的局部变量

我很难理解以下程序的意外输出:

class ThreadTest { static void Main() { for(int i = 0; i  Console.Write(i)).Start(); } } 

查询:在不同线程中运行的不同代码是否具有单独的堆栈? 如果是,那么变量应该保留它们的值,因为int是值类型?

每个线程都有自己的堆栈。 您面临的问题与堆栈无关。 问题是它为匿名委托生成代码的方式。 使用像refelector这样的工具来理解它生成的代码。 以下将解决您的问题:

 static void Main() { for (int i = 0; i < 10; i++) { int capture = i; new Thread(() => Console.Write(capture)).Start(); } } 

在引擎盖下

无论何时在匿名委托中使用外部作用域(在您的情况变量i中)的变量,编译器都会生成一个新类,该类包含匿名函数以及它从外部作用域使用的数据。 因此,在您的情况下,生成的类包含 – 一个函数和数据成员来捕获变量i的值。 类定义类似于:

 class SomeClass { public int i { get; set; } public void Write() { Console.WriteLine(i); } } 

编译器重写代码如下:

 SomeClass someObj = new SomeClass(); for (int i = 0; i < 10; i++) { someObj.i = i; new Thread(someObj.Write).Start(); } 

因此问题 - 你正面临着。 捕获变量时,编译器执行以下操作:

 for (int i = 0; i < 10; i++) { SomeClass someObj = new SomeClass(); someObj.i = i; new Thread(someObj.Write).Start(); } 

注意SomeClass实例化的区别。 捕获变量时,它会创建与迭代次数一样多的实例。 如果您没有捕获变量,它会尝试对所有迭代使用相同的实例。

希望,以上解释将澄清您的疑问。

谢谢

是的,线程有自己的堆栈。 但是在这里你也有变量捕获的问题。 尝试将代码更改为:

 class ThreadTest { static void Main() { for(int i = 0; i < 10; i++) { int j = i; new Thread(() => Console.Write(j)).Start(); } } } 

注意输出的变化? 每个线程都是通过引用变量而不是值来启动的。 当我插入int j = i; 我们正在打破变量捕获。 您的意外输出与线程的关系不如关闭。