2009-09-25 70 views
7

read該代碼的這一部分可能會導致死鎖:DeadLock Process.StandardOutput.ReadToEnd()中的問題;

Process p = new Process(); 

p.StartInfo.UseShellExecute = false; 
p.StartInfo.RedirectStandardOutput = true; 
p.StartInfo.FileName = "Write500Lines.exe"; 
p.Start(); 
p.WaitForExit(); 
string output = p.StandardOutput.ReadToEnd(); 

因爲

死鎖條件可能會導致如果 父進程調用p.WaitForExit 之前p.StandardOutput.ReadToEnd和 子進程寫入足夠多的文本 來填充重定向的流。父進程 將無限期地等待 以使子進程退出。 子進程將無限期等待 ,父進程將從完整的 StandardOutput流中讀取。

但我不太清楚爲什麼。我的意思是,在這種情況下,父母的過程是什麼,孩子是什麼?

+1

您可能對[此文章](http://www.codeducky.org/process-handling-net)感興趣,它解釋了使用.NET流程流的死鎖和其他複雜性。 – ChaseMedallion 2014-08-30 00:08:45

回答

11

總之這是可能發生的事情:

應用A(你上面的代碼)啓動子進程B和重定向標準輸出。然後A等待B過程退出。當A等待B退出時,B產生輸出到輸出流(A已重定向)。此流具有有限的緩衝區大小。如果緩衝區已滿,需要將其清空以便B能夠繼續寫入緩衝區。由於A在B退出前沒有讀取數據,所以最終會出現B將等待輸出緩衝區清空的情況,而A將等待B退出。兩人都在等待對方採取行動,而你們陷入僵局。

你可以試試下面的代碼來演示該問題:

ProcessStartInfo psi = new ProcessStartInfo(); 
psi.FileName = "cmd"; 
psi.Arguments = @"/c dir C:\windows /s"; 
psi.RedirectStandardOutput = true; 
psi.UseShellExecute = false; 
Process p = Process.Start(psi); 
p.WaitForExit(); 
string output = p.StandardOutput.ReadToEnd(); 

這將(moste可能)產生,其中輸出流滿的情況下,這樣子進程(在這種情況下"cmd")將等待要清除它,而上面的代碼將等待cmd完成。

+0

謝謝你的清晰解釋。 – Graviton 2009-09-25 08:23:03

+0

那麼......我怎麼能用一些參數運行'sqlcmd.exe'這樣的進程,時間不會超過5分鐘,並且可以讀取儘可能多的stdout和stderr,因爲我可以捕獲它們?我找不到一個乾淨而簡單的方法來做到這一點。 – 2011-04-05 19:46:50

+0

優秀的解釋! – 2012-10-06 23:11:17

0

父進程是調用p.Start()的進程。我想這是你的應用程序(調用者)。 子進程是p或換句話說,被調用者。