C#无法加入主线程

Posted

技术标签:

【中文标题】C#无法加入主线程【英文标题】:C# Cannot join main thread 【发布时间】:2018-12-05 13:35:29 【问题描述】:

我有非常简单的代码,我无法理解它的行为。

class Program

    static void Main(string[] args)
    
        // Get reference to main thread
        Thread mainThread = Thread.CurrentThread;

        // Start second thread
        new Thread(() =>
        
            Console.WriteLine("Working...");
            Thread.Sleep(1000);

            Console.WriteLine("Work finished. Waiting for main thread to end...");
            mainThread.Join();        // Obviously this join cannot pass

            Console.WriteLine("This message never prints. Why???");
        ).Start();

        Thread.Sleep(300);
        Console.WriteLine("Main thread ended");
    

这个永无止境的程序的输出是:

在职的... 主线程结束 工作完成。等待主线程结束...

为什么线程的代码卡在Join() 方法调用上?通过其他打印输出可以发现,在Join()调用之前,mainThread的属性IsAlive设置为false,ThreadStateBackground, Stopped, WaitSleepJoin。消除睡眠也没有任何区别。

这种行为的原因是什么? Join() 方法和Main 方法的执行到底有什么奥秘?

【问题讨论】:

主线程终止通常与进程终止同时发生。我猜这是对你的代码做你不想要的事情 【参考方案1】:

Join() 按您的预期工作,这里的问题是假设运行Main() 的线程在Main() 返回时终止,但情况并非总是如此。

.NET 框架调用您的Main() 方法,当方法返回时,框架会在主线程(以及进程)退出之前执行额外的代码。具体来说,框架作为 post-Main 代码的一部分所做的事情之一是等待所有前台线程退出。

这实质上会导致典型的死锁情况 - 主线程正在等待您的工作线程退出,而您的工作线程正在等待主线程退出。

当然,如果你让你的工作线程成为后台线程(通过在启动它之前设置IsBackground = true),那么后Main 代码将不会等待它退出,从而消除了死锁。但是您的Join()仍然永远不会返回,因为当主线程退出时,进程也会退出。

有关在 Main() 之前和之后运行的框架内部的更多详细信息,您可以查看 GitHub 上的 .NET Core 代码库。运行Main()的整体方法是Assembly::ExecuteMainMethod,运行之后Main()返回的代码是Assembly::RunMainPost

【讨论】:

是的,这比我的回答要好。 +1用于链接源。我正打算自己做。 这是非常好的解释。我也很高兴链接的支持该声明的源代码。我不知道在哪里可以找到这段代码。 只是 mainThread 状态和 isAlive 属性值令人困惑。这也有原因吗?

以上是关于C#无法加入主线程的主要内容,如果未能解决你的问题,请参考以下文章

引用 C# 中的主线程

c#多线程

C# 退出程序方法

多线程问题,,如何让所有子线程结束后再执行主线程,,要C#

C# WinForm程序中强制退出程序以及启动程序

C#程序退出的几种方法