Skip to content

Using Process.BeginOutputReadLine can lead to lost stdout lines #18789

@joelverhagen

Description

@joelverhagen

When writing code that creates child processes and needs to capture stdout, I have found that lines of output go missing the following condition:

  • lots of parallelism...
  • ProcessStartInfo.RedirectStandardOutput = true
  • Process.OutputDataReceived += CollectLines (that is, using the async flow)
  • Process.BeginOutputReadLine()
  • Process.WaitForExit(int.MaxValue)

Note that passing -1 (infinite timespan) to WaitForExit does not cause lines go missing (based on my own testing).

I have created a little demo app to do this. It repro's on both netcoreapp1.0 and net45: processredirect.zip. Just use dotnet run to try it out.

That being said, you can capture stdout by using Process.StandardOutput (which is a StreamReader). However to consume this asynchronously and safely you need to use background threads/tasks. In other words:

stdout capture method using infinite timeout is flaky
StandardOutput StreamReader yes no
StandardOutput StreamReader no no
OutputDataReceived event yes no
OutputDataReceived event no yes

I think this a problem because it's pretty easy to step into this pitfall. Using the events to capture output is very convenient since you don't have to worry about making background threads or tasks. Also, the internet recommends this method:

I have only tried this on Windows, .NET Framework 4.5 and .NET Core (netcoreapp1.0). Also, all of this information is related to stdout, but I imagine stderr has the same problem. My dotnet info is:

Microsoft .NET Core Shared Framework Host

  Version  : 1.0.1
  Build    : cee57bf6c981237d80aa1631cfe83cb9ba329f12

> dotnet --version
1.0.0-preview2-003131

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions