【问题标题】:C# Cannot join main threadC#无法加入主线程
【发布时间】: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 方法的执行到底有什么奥秘?

【问题讨论】:

  • 主线程终止通常与进程终止同时发生。我猜这是对你的代码做你不想要的事情

标签: c# .net multithreading 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 属性值令人困惑。这也有原因吗?
猜你喜欢
  • 1970-01-01
  • 2020-08-04
  • 1970-01-01
  • 2014-02-12
  • 1970-01-01
  • 2018-02-16
  • 2011-06-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多