2010-05-04 26 views
4

我開始運行控制檯應用程序的C#應用​​程序中的一個進程。我重定向了標準輸入和輸出,並且能夠通過StandardOutput.ReadLine()讀取幾行。我確信我已正確配置了ProcessStartInfo。StandardOutput.EndOfStream掛起

控制檯應用程序在啓動時會輸出幾行(以「標記」行結尾),然後等待輸入。接收到輸入後,再次輸出幾行(以「標記」行結束),依此類推。我的意圖是從它讀取直到我收到「標記」行,在這一點上,我知道發送適當的輸入字符串。

我的問題是,經過多次迭代,程序掛起。暫停調試器往往會將掛起放在對StandardOutput.EndOfStream的調用中。這是在下面的測試代碼的情況:

while (!mProcess.StandardOutput.EndOfStream) // Program hangs here. 
{ 
    Console.WriteLine(mProcess.StandardOutput.ReadLine()); 
} 

當我測試的「標記」行了,我得到同樣的,如果我試圖讀線後訪問StandardOutput.EndOfStream掛的:

string line = ""; 
while (!isMarker(line)) 
{ 
    line = mProcess.StandardOutput.ReadLine(); 
} 
bool eos = mProcess.StandardOutput.EndOfStream; // Program hangs here. 

我會怎麼做,導致此屬性執行如此可怕?

回答

9

不能可靠地在這裏使用EndOfStream。如果StreamReader.EndOfStream屬性沒有緩衝字符,它將調用StandardOutput.Read()。如果進程沒有向其輸出管道發送任何內容並且沒有關閉它,那麼Read()調用將會阻塞。這是非常有保證的,因爲它會等待輸入。只有當流程關閉了輸出管道的末端並且StreamReader已經消耗了所有緩衝字符時,EndOfStream纔會返回true。在節目結束時。

使用BeginOutputReadLine()可能是檢測「標記」行的更好方法。注意回調發生在另一個線程上。還要注意,不需要等待進程發送標記,您寫入的任何內容都將被緩存,直到進程準備好讀取它爲止。注意緩衝區很小,可能出現死鎖。

0

你有沒有等待進程結束之前從中讀取的標準輸出:

mProcess.WaitForExit(); 
+1

否;目的是與控制檯應用程序進行交互。 – TreDubZedd 2010-05-04 17:33:39

1

有許多路徑可以在與進程類進行交互時爲其創建死鎖。微軟在MSDN site here上描述了他們。這是我如何稱呼它。注意ErrorDataReceived和OutputDataReceived的處理以及對BeginErrorReadLine和BeginOutputReadLine的調用。這可以通過讓父進程異步讀取流來消除死鎖情況。注意:RunProcessResponse是我自己的小封裝數據傳輸對象。

Public Function RunProcess(ByVal executableFileName As String, ByVal arguments As String, ByVal workingDirectory As System.String) As RunProcessResponse 
    Dim process As System.Diagnostics.Process = Nothing 
    Dim response As RunProcessResponse 

    Try 
     process = New System.Diagnostics.Process() 
     Dim psInfo As New System.Diagnostics.ProcessStartInfo() 
     Dim errorString As System.String = String.Empty 
     Dim outputString As System.String = String.Empty 


     If Not System.String.IsNullOrEmpty(workingDirectory) Then 
      psInfo.WorkingDirectory = workingDirectory 
     End If 

     psInfo.FileName = executableFileName 
     psInfo.Arguments = arguments 
     psInfo.WindowStyle = ProcessWindowStyle.Hidden 
     psInfo.CreateNoWindow = True 
     psInfo.RedirectStandardError = True 
     psInfo.RedirectStandardOutput = True 
     psInfo.UseShellExecute = False 

     AddHandler process.ErrorDataReceived, Sub(sender As Object, args As DataReceivedEventArgs) 
                If args.Data IsNot Nothing Then 
                 errorString &= args.Data & vbCrLf 
                End If 
               End Sub 
     AddHandler process.OutputDataReceived, Sub(sender As Object, args As DataReceivedEventArgs) 
                If args.Data IsNot Nothing Then 
                 outputString &= args.Data & vbCrLf 
                End If 
               End Sub 

     process.StartInfo = psInfo 
     process.Start() 

     process.BeginErrorReadLine() 
     process.BeginOutputReadLine() 
     process.WaitForExit() 

     response = New RunProcessResponse(errorString, outputString, process.ExitCode) 

     Return response 
    Finally 
     If process IsNot Nothing Then 
      process.Dispose() 
     End If 
    End Try 
End Function 
0

如果你知道,有沒有更多的標準輸入您的後:

while (!mProcess.StandardOutput.EndOfStream) 

循環,你可以關閉標準輸入有:

mProcess.StandardInput.Close(); 

要通知沒有更多輸入。只要標準投入是開放的,就有可能獲得更多投入,從而產出更多;因此,標準輸出將永遠達不到EndOfStream。