代码之家  ›  专栏  ›  技术社区  ›  TreDubZedd

StandardOutput.Endofstream挂起

  •  4
  • TreDubZedd  · 技术社区  · 15 年前

    我正在运行控制台应用程序的C应用程序中启动一个进程。我已经重定向了标准输入和输出,并且能够通过standard output.readline()读取一些行。我确信ProcessStartInfo配置正确。

    控制台应用程序在启动时输出几行(以“标记”行结尾),然后等待输入。在接收到输入之后,它再次输出一些行(以“标记”行结束),依此类推。我的目的是从中读取行,直到我收到“标记”行,在这一点上,我知道发送适当的输入字符串。

    我的问题是,经过多次迭代,程序挂起。暂停调试器往往会将挂起置于对StandardOutput.EndOfStream的调用中。以下测试代码就是这种情况:

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

    当我测试“marker”行时,如果在读取该行后尝试访问standardoutput.endofstream,我会得到相同的挂起:

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

    我该怎么做才能让这家酒店表现得如此糟糕?

    4 回复  |  直到 9 年前
        1
  •  9
  •   Hans Passant    15 年前

    你不能在这里可靠地使用endofstream。如果streamreader.endofstream属性没有缓冲任何字符,它将调用standardoutput.read()。如果进程没有向其输出管道发送任何内容并且没有关闭它,那么read()调用将阻塞。因为它将等待输入,所以几乎可以保证会发生这种情况。EndofStream将不会返回true,除非进程关闭了其输出管道的末端,并且StreamReader已消耗了其所有缓冲字符。在程序终止时。

    使用beginOutputReadline()可能是检测“marker”行的更好方法。注意回调发生在另一个线程上。还要注意,不需要等待进程发送标记,您所写的任何内容都将被缓冲,直到进程准备好读取标记为止。注意,缓冲区很小,可能出现死锁。

        2
  •  1
  •   Matt Poland    14 年前

    在与流程类交互时,有许多路径可以为其创建死锁。微软在 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
    
        3
  •  0
  •   Darin Dimitrov    15 年前

    在从标准输出读取之前,是否等待过程完成:

    mProcess.WaitForExit();
    
        4
  •  0
  •   Kenton Groombridge    9 年前

    如果您知道在您的之后没有更多的标准输入:

    while (!mProcess.StandardOutput.EndOfStream) 
    

    循环,您可以使用以下命令关闭标准输入:

    mProcess.StandardInput.Close();
    

    表示不再有输入。只要标准输入是开放的,就有可能产生更多的输入,从而产生更多的输出;因此,标准输出永远不会到达流内。