2013-01-17 16 views
11

Mój kolega znalazł problem z naszym kodem i zajęło trochę czasu, aby znaleźć dokładnie to, co się dzieje, ale najlepiej można to wykazać na podstawie tego prostego przykładu:Zapisywanie na konsoli przy użyciu Task.Run() kończy się niepowodzeniem.

// 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(); 
    } 
} 

Jest oczywiste, że dzięki temu pisanie na konsolę w dowolnym miejscu z głównego wątku pozwoli również wątkowi tła pisać do konsoli, ale staramy się zrozumieć, dlaczego tak się dzieje. Czy ktoś może wyjaśnić, co pisanie na konsolę z głównego wątku zapewnia, że ​​pierwszy fragment nie działa?

+0

Nie opisano, co dzieje się w przypadku niepowodzenia. Na moim pudełku, wydaje się, że zawiesi się, dopóki nie uderzysz, w którym momencie drukuje. –

+0

@JonSkeet Tak, to jest zachowanie, które widzę – kevinawalker

Odpowiedz

4

Mam podejrzenia co do tego, co się dzieje. Co mam zauważył:

  • Jeśli nie nic z wyjściem konsoli przed uruchomieniem ReadKey, jest w porządku. Obejmuje to ściągam Console.Out ale nie to
  • używając Jeśli umieścisz opóźnienia w taki sposób, że Console.WriteLine wezwanie zaczyna przed wywołaniem Console.ReadKey, to jest w porządku (i można mieć wiele WriteLine wzywa podczasReadKey czeka

Podejrzewam, że pierwsza operacja korzystania z konsoli uzyskuje blokadę podczas inicjalizacji (w celu uniknięcia dwukrotnego zainicjowania) i że ReadKey metoda utrzymuje blokadę do momentu odczytania klucza. lain każdy program, który do tej pory prowadziłem.

Operacje, które wykonują hipotetyczną inicjalizację są jednak interesujące - odczytanie Console.Out "rozwiązuje" problem, ale odczyt z Console.In nie.

Podejrzewam, że ReadKey inicjalizuje dane wyjściowe, ponieważ wartość jest nadal wysyłana do konsoli ... ale nie chciałbym jej przeklinać.

Co ciekawe, użycie Console.ReadLine() zamiast Console.ReadKey() nie powoduje problemu w pierwszej kolejności.

+0

Z pewnością interesujące jest to, że 'Console.ReadLine()' nie powoduje tego samego problemu. Dzięki za poświęcenie czasu – kevinawalker

4

Właściwie pierwszy przypadek nie zawiedzie. "Hello World" pojawia się tuż przed zakończeniem Aplikacji. To jest klasyczny Race Condition. W pierwszym przypadku, Console.ReadKey() z głównego wątku pokonuje zadanie, a w drugim przypadku zadanie wygrywa. Niestety, nie mogę ci powiedzieć, dlaczego pisanie pustego ciągu powoduje, że zadanie wygrywa.

+0

To jest rzeczywiście rozwiązanie. –

+0

Nie sądzę, że to prawda. To nie jest tak, jak wywołanie Console.WriteLine dzieje się po wywołaniu w Console.ReadLine ma * zakończone * - w przeciwnym razie, jeśli poczekasz chwilę, zobaczysz wynik. Wydaje mi się, że to chyba jakiś problem z inicjalizacją. –

+0

Albo, aby być bardziej zrozumiałym - uważam, że jest to warunek wyścigu, ale tylko pod względem tego, który wywołanie * rozpoczyna się * pierwszy i tylko jeśli 'Console.ReadKey' jest pierwszym wywołaniem konsoli, z których żadne nie są jasne w odpowiedzi. –

Powiązane problemy