Подтвердить что ты не робот

Запись на консоль с использованием функции Task.Run()

Мой коллега нашел проблему с нашим кодом, и потребовалось некоторое время, чтобы выследить, что именно происходит, но это лучше всего продемонстрировать на этом простом примере:

// Fails
class Program
{
    static void Main(string[] args)
    {
        Task.Run(() => Console.WriteLine("Hello World"));
        Console.ReadKey();
    }
}

// Works fine
class Program
{
    static void Main(string[] args)
    {
        Console.Write(String.Empty);
        Task.Run(() => Console.WriteLine("Hello World"));
        Console.ReadKey();
    }
}

Из-за того, что писать на консоль в любом месте из основного потока, это позволяет фоновому потоку также писать на консоль, но мы изо всех сил пытаемся понять, почему это происходит. Может ли кто-нибудь объяснить, что пишут на консоль из основного потока, что первый фрагмент не делает?

4b9b3361

Ответ 1

У меня есть подозрение, что происходит. То, что я наблюдал:

  • Если вы делаете что-либо с выходом консоли перед запуском ReadKey, это нормально. Сюда входит выборка Console.Out, но не ее использование
  • Если вы положили задержку так, что вызов Console.WriteLine начинается до вызова Console.ReadKey, это нормально (и вы можете иметь несколько вызовов WriteLine, пока ReadKey ожидает

Я подозреваю, что первая операция с использованием консоли получает блокировку для инициализации (чтобы избежать ее инициализации дважды) и что метод ReadKey сохраняет фиксацию до тех пор, пока ключ не будет прочитан. Это наверняка объяснит каждую программу, которую я выполнил до сих пор.

Операции, выполняющие гипотетическую инициализацию, интересны, хотя чтение Console.Out "исправляет" проблему, но чтение из Console.In не делает.

Я подозреваю, что ReadKey инициализирует вывод, потому что значение все еще эхом отдано на консоль... но я не хотел бы ругаться.

Интересно, что использование Console.ReadLine() вместо Console.ReadKey() не вызывает проблемы в первую очередь.

Ответ 2

Собственно, первый случай не подводит. "Hello World" появляется перед тем, как приложение завершится. Это классическое Состояние гонки. В первом случае Console.ReadKey() из основного потока выполняет задачу, а во втором - выигрывает задача. К сожалению, я не могу сказать вам точно, почему запись пустой строки заставляет задачу побеждать.