StandardOutput.EndOfStream Hangs

前端 未结 4 890
情书的邮戳
情书的邮戳 2020-12-20 23:21

I\'m starting a process within my C# application which runs a console application. I\'ve redirected standard input and output, and am able to read a few lines via StandardO

相关标签:
4条回答
  • 2020-12-20 23:42

    There are numerous paths for which you can create a deadlock when interacting with a process class. Microsoft describes them on the MSDN site here. Here is how I call it. Notice the handling of ErrorDataReceived and OutputDataReceived and the calls to BeginErrorReadLine and BeginOutputReadLine. This eliminates deadlock scenarios by having the parent process read the streams asynchronously. NOTE: RunProcessResponse is my own little wrapper data transfer object.

    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 讨论(0)
  • 2020-12-20 23:43

    If you know that there is no more standard input after your:

    while (!mProcess.StandardOutput.EndOfStream) 
    

    loop, you can close standard input with:

    mProcess.StandardInput.Close();
    

    To signal that there is no more input. As long as standard input is open, there is the potential for more input, thus more output; therefore, standard output will never reach EndOfStream.

    0 讨论(0)
  • 2020-12-20 23:48

    Did you wait for the process to finish before reading from it's standard output:

    mProcess.WaitForExit();
    
    0 讨论(0)
  • 2020-12-20 23:51

    You cannot use EndOfStream reliably here. The StreamReader.EndOfStream property will call StandardOutput.Read() if it doesn't have any characters buffered. That Read() call will block if the process isn't sending anything to its output pipe and doesn't close it. Which is pretty much guaranteed to happen since it will be waiting for input. EndOfStream won't return true until the process has closed its end of the output pipe and the StreamReader has consumed all its buffered characters. At program termination.

    Using BeginOutputReadLine() might be a better way to detect the "marker" line. Beware that the callback happens on another thread. Also note that it shouldn't be necessary to wait for the process to send the marker, anything you write will be buffered until the process is ready to read it. Beware that the buffers are smallish, deadlock is possible.

    0 讨论(0)
提交回复
热议问题