Ответ 1
Есть много дублирующих вопросов по этой проблеме, которые точно не соответствуют вашему делу. Вы можете увидеть эту проблему, используя окно отладки Debug + Windows + Threads. Найдите поток таймера и дважды щелкните его. Посмотрите на окно Call Stack, чтобы увидеть:
mscorlib.dll!System.Console.InputEncoding.get() + 0x66 bytes
System.dll!System.Diagnostics.Process.StartWithCreateProcess(System.Diagnostics.ProcessStartInfo startInfo) + 0x7f5 bytes
System.dll!System.Diagnostics.Process.Start() + 0x88 bytes
ConsoleApplication70.exe!Program.RunProcess() Line 43 + 0xa bytes C#
ConsoleApplication70.exe!Program.OnTimerElapsed(object sender, System.Timers.ElapsedEventArgs e) Line 28 + 0x5 bytes C#
// etc...
Нить зашла в тупик на получателе свойств Console.InputEncoding. Используется классом Process для определения того, какая кодировка должна использоваться для перевода перенаправленного вывода процесса в строки.
Это специфично для .NET 4.5, оно также будет влиять на приложения, которые нацелены на 4.0 на машине с установленным 4.5, поскольку она не является бок о бок версией .NET. Тупик вызван вызовом метода Console.ReadKey() в вашем основном потоке. Теперь он получает блокировку, предотвращающую взаимодействие других потоков с консолью. Это было довольно глобальное изменение в программном обеспечении Microsoft, CRT, который используется в приложениях C/С++, созданных VS2012, также добавил эту блокировку. Точная причина для меня не так понятна, но, безусловно, нужно что-то делать, когда консольный вывод не смешивается с консольным вводом, когда ваша программа запрашивает ввод. Именно поэтому свойство InputEncoding необходимо также блокировать, но это немного сложно объяснить, но он соответствует шаблону сериализации доступа к вводу в консоль. Это, конечно, является большим сюрпризом для многих программистов, особенно тех, которые пишут небольшие тестовые приложения, которые проверяют многопоточный код, как и вы. Бит неудачи для TDD.
Обходной путь немного неприятный, TDD мудрый, вам нужно прекратить использование Console.ReadKey(), чтобы избежать тупика. Реальные программы будут использовать метод WaitOne() для AutoResetEvent, чтобы знать, что рабочий поток завершил выполнение. Или CountDownEvent.Wait(), больше в порядке с проверкой кода пару раз. Etcetera.
UPDATE: этот сценарий блокировки был разрешен в обновлении службы для .NET 4.5. Включите Windows Update на своем компьютере, чтобы получить его.