我有非常简单的代码,我无法理解其行为。
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");
}
}
这个永无止境的程序的输出是:
Working... Main thread ended Work finished. Waiting for main thread to end...
为什么线程的代码卡在Join()
方法调用中?通过其他打印输出可以发现,在调用Join()
之前,IsAlive
的属性mainThread
已设置为false,而ThreadState
为Background, Stopped, WaitSleepJoin
。同样,消除睡眠也没有任何区别。
此行为的原因是什么? Join()
方法和Main
方法的执行有什么奥秘?
答案 0 :(得分:3)
Join()
可以按预期工作,这里的问题是假设运行Main()
的线程在Main()
返回时终止,但并非总是如此。
您的Main()
方法由.NET框架调用,当该方法返回时,框架将在主线程(并因此退出进程)退出之前执行其他代码。具体地说,该框架作为后Main代码的一部分要做的一件事就是等待所有前台线程退出。
这实际上会导致典型的死锁情况-主线程正在等待您的工作线程退出,而工作线程正在等待主线程退出。
当然,如果您将工作线程设为后台线程(通过在启动线程之前设置IsBackground = true
),则后主代码将不等待其退出,从而消除了死锁。但是,您的Join()
将 still 永不返回,因为当主线程退出时,该进程也会退出。
有关在Main()
之前和之后运行的框架内部的更多详细信息,您可以查看GitHub上的.NET Core代码库。运行Main()
的总体方法是Assembly::ExecuteMainMethod
,而在之后 Main()
返回的代码是Assembly::RunMainPost
。
答案 1 :(得分:-1)
我认为您理解Join很好。
据我了解,C#中的主线程很特殊。主线程调用您的Main
方法后,执行返回到框架,该框架等待进程中的其他子线程终止。
编辑:这是一个示例,显示您编写的代码在您不是主线程的情况下有效。
static void Main(string[] args)
{
Thread primaryThread = null;
primaryThread = new Thread(() =>
{
// Start second thread
new Thread(() =>
{
Console.WriteLine("Working...");
Thread.Sleep(1000);
Console.WriteLine("Work finished. Waiting for primary thread to end...");
primaryThread.Join();
Console.WriteLine("This message does print.");
}).Start();
Thread.Sleep(300);
Console.WriteLine("primary thread ended");
});
primaryThread.Start();
}