帮助理解C#和多线程

rau*_*and 4 c# multithreading

嗨,我正在阅读"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();
    }
}
Run Code Online (Sandbox Code Playgroud)

}

输出: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.

谢谢.

Jon*_*eet 5

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

这是一个非常常见的问题,但在线程教程中看到它真的很遗憾.(我希望这不是我的一篇文章!请告诉我们你在哪里读这篇文章.)Eric Lippert在他的博客文章中非常仔细地写了这篇文章,"关闭了认为有害的循环变量" - 第1部分 ; 第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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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