2013-01-17 85 views
11

我的一位同事發現我們的代碼存在問題,需要花費一段時間才能查明發生了什麼,但可以通過以下簡單示例最好地演示:使用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(); 
    } 
} 

從這個問題可以清楚地看出,從主線程的任何位置寫入控制檯都會允許後臺線程寫入控制檯,但我們正在努力理解爲什麼發生這種情況。任何人都可以解釋從主線程向控制檯寫入的內容是否實現了第一個片段不會呢?

+0

你沒有描述你的失敗案件會發生什麼。在我的盒子裏,它似乎一直掛着,直到你打回來,然後打印。 –

+0

@JonSkeet是的,這是我看到的行爲 – kevinawalker

回答

4

我懷疑發生了什麼事。我觀察到:

  • 如果在啓動之前ReadKey任何用控制檯的輸出,它的罰款。這包括獲取Console.Out但如果你把一個延遲,使得Console.WriteLine呼叫Console.ReadKey調用之前開始,它的罰款(你可以有多個WriteLine調用ReadKey等待
不使用它
  • 我懷疑第一次使用控制檯的操作獲取初始化的鎖(以避免它被初始化兩次),並且ReadKey方法保持鎖直到一個密鑰被讀取。躺在我到目前爲止運行的每一個程序中。

    雖然執行假設初始化的操作很有趣 - 讀取Console.Out「修復」了該問題,但從Console.In讀取的操作沒有。

    我懷疑ReadKey初始化輸出,因爲值仍然回顯到控制檯...但我不想發誓。

    有趣的是,使用Console.ReadLine()而不是Console.ReadKey()首先不會導致問題。

  • +0

    'Console.ReadLine()'不會導致相同的問題,這當然很有趣。感謝您抽出寶貴的時間 – kevinawalker

    4

    實際上,第一種情況並不失敗。 「Hello World」在應用程序結束前出現。這是一個經典的Race Condition。在第一種情況下,來自主線程的Console.ReadKey()擊敗任務,而在第二種情況下,任務獲勝。不幸的是,我不能告訴你究竟爲什麼寫空字符串會使任務獲勝。

    +0

    這確實是解決方案。 –

    +0

    我不認爲這是正確的。它不像調用Console.WriteLine那樣,在調用Console.ReadLine之後發生* *完成* - 否則如果您等待一段時間,您會看到輸出。這似乎是某種初始化問題,我想。 –

    +0

    或者更清楚一點 - 我相信這是一種競爭條件,但僅限於第一次調用*開始時,以及僅當「Console.ReadKey」是第一次調用控制檯時,兩者都不會在答案中清楚。 –