简体   繁体   中英

C# Cannot join main thread

I have very simple code which behavior I cannot understand.

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");
    }
}

Output of this never-ending program is:

Working...
Main thread ended
Work finished. Waiting for main thread to end...

Why the threads' code get stuck on the Join() method call? By other print outs can be find out, that already before Join() call, the property IsAlive of mainThread is set to false and the ThreadState is Background, Stopped, WaitSleepJoin . Also removing sleeps doesn't make any difference.

What's the reasoning for this behavior? What mystery is under the hood of Join() method and execution of Main method?

Join() works as you expect it to, the issue here is with the assumption that the thread running Main() terminates when Main() returns, which is not always the case.

Your Main() method is called by the .NET framework, and when the method returns, there is additional code executed by the framework before the main thread (and hence the process) exits. Specifically, one of the things the framework does as part of the post-Main code is wait for all foreground threads to exit.

This essentially results in a classic deadlock situation - the main thread is waiting for your worker thread to exit, and your worker thread is waiting for the main thread to exit.

Of course, if you make your worker thread a background thread, (by setting IsBackground = true before starting it) then the post-Main code won't wait for it to exit, eliminating the deadlock. However your Join() will still never return because when the main thread does exit, the process also exits.

For more details on the framework internals that run before and after Main() , you can take a look at the .NET Core codebase on GitHub. The overall method that runs Main() is Assembly::ExecuteMainMethod , and the code that runs after Main() returns is Assembly::RunMainPost .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM