【问题标题】:Concurrent Threads using same method使用相同方法的并发线程
【发布时间】:2012-10-04 11:58:03
【问题描述】:

如果我生成各种线程,并告诉它们都使用相同的方法:

internal class Program {

    private static DoSomething() {

        int result = 0;
        Thread.Sleep(1000);
        result++;
        int ID = Thread.CurrentThread.ManagedThreadId;
        Console.WriteLine("Thread {0} return {1}", ID, result);
    }

    private static Main() {

        Thread[] threads = new Thread[50];

        for (int i = 0; i < 50; i++)
            threads[i] = new Thread(DoSomething);

        foreach (Thread t in threads)
            t.Start();
    }
}   

所有线程会共享同一个堆栈吗?当我运行程序时,所有线程都返回 1,所以我猜答案是否定的,但这是否意味着 CLR 在内存中制作了不同的方法副本?

【问题讨论】:

    标签: c# multithreading stack


    【解决方案1】:

    这是否意味着 CLR 在内存中制作了不同的方法副本?

    没有。它有助于理解 .NET 程序中的内存是如何划分的。我将跳过很多次要的实现细节来绘制大图。您可以将内存细分为以下类别:

    • 垃圾收集堆。对象存储在那里,您可以使用 new 运算符从中分配存储空间(结构除外)。它会根据需要增长,用完会产生 OutOfMemoryException。

    • 加载程序堆。 AppDomain 的任何静态内容都存储在那里。许多小部分,但重要的是静态变量、类型信息(通过反射检索的那种)和即时编译代码的存储。它根据需要增长,使用太多很难做到。

    • 堆栈。处理器的核心数据结构。不在 C# 中抽象它是 C# 生成快速程序的一个重要原因。堆栈存储调用方法时的返回地址、传递给方法的参数和方法的局部变量。默认情况下,堆栈为 1 兆字节且不能增长。如果您使用过多此站点的名称,您的程序将失败,这是一个严重且难以诊断的故障,因为处理器无法继续执行代码。

    一个线程可以查看所有这些内存类别,但最后一个类别有所不同。每个线程都有自己的堆栈。这就是为什么它能够独立于其他线程运行自己的方法的原因。然而,它使用与任何其他线程完全相同的代码,加载器堆是共享的。假设多个线程执行相同的方法。它共享相同的垃圾收集堆和静态变量。这使得编写线程代码困难,您必须确保线程不会踩到其他线程也使用的对象和静态变量。 lock 关键字的一个重要原因。

    【讨论】:

    • 非常感谢,这很有帮助!
    【解决方案2】:

    不,每个线程都有自己的堆栈。而且只有一个 DoSomething。每个线程都可以从任何地方访问任何类型的数据,是否安全这是另一个问题。将 DoSomething 视为只是数据,一个整数,每个线程都会递增它。现在想象 DoSomething 是一个函数指针,你将它的地址(本质上是一个 int)传递给每个线程。

    【讨论】:

      【解决方案3】:

      要回答您的问题,不,内存中没有该方法的多个副本。 只有一个副本和多个线程通过它运行。就连对象 在内存中在多个线程之间共享。这就是导致内存损坏的原因。

      通过this 更好地了解线程。

      编辑: 另外,类似的问题here

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-11-24
        • 1970-01-01
        • 2015-07-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-31
        • 2016-09-06
        相关资源
        最近更新 更多