Join()
работает так, как вы ожидаете, проблема здесь заключается в предположении, что поток, выполняющий Main()
, завершается, когда возвращается Main()
, что не всегда так.
Ваш метод Main()
вызывается платформой .NET, и когда метод возвращается, существует дополнительный код, выполняемый платформой перед выходом из основного потока (и, следовательно, процесса). В частности, одна из вещей, которые фреймворк делает как часть кода после Main, - это ожидание выхода всех потоков переднего плана.
По сути, это приводит к классической тупиковой ситуации: основной поток ожидает выхода вашего рабочего потока, а ваш рабочий поток ожидает выхода основного потока.
Конечно, если вы сделаете свой рабочий поток фоновым потоком (установив IsBackground = true
перед его запуском), тогда код post-Main не будет ждать его выхода, что устраняет тупик. Однако ваш Join()
будет все еще никогда не вернется, потому что, когда основной поток завершает работу, процесс также завершается.
Для получения более подробной информации о внутренностях фреймворка, которые выполняются до и после Main()
, вы можете взглянуть на кодовую базу .NET Core на GitHub. Общий метод, который запускается Main()
, равен Assembly::ExecuteMainMethod
, а код, который запускается после возврата Main()
, равен Assembly::RunMainPost
.