Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to asynchronously read the standard output stream and standard error stream at once

Tags:

c#

.net

process

I want to read the ouput of a process in the form as is in a console (standard output is blended with standard error in one stream). Is there a way how to do it?

I was thinking about using

ProcessStartInfo.UseShellExecute = true;  

but then I cannot read asynchronously the output. If I set

process.ProcessStartInfo.UseShellExecute = false;  
process.StartInfo.RedirectStandardOutput = true;
process.OutputDataReceived += new DataReceivedEventHandler(partialOutputHandler);

then I can read standard output (I can do the same for standard error) but I don't know how to simulate the behavior of console (the blending of stdout and stderr).

This is similar to Linux which has the feature of redirecting standard error stream to the standard output stream; how?

like image 928
Martin Vseticka Avatar asked Sep 24 '12 13:09

Martin Vseticka


3 Answers

Do you mean something like this?

SynchronizationContext _syncContext;
MyForm()
{
    _syncContext = SynchronizationContext.Current;
}

void StartProcess()
{
    using (var process = new Process
        {
            StartInfo = new ProcessStartInfo
            {
                FileName = "myProcess.exe",
                UseShellExecute = false,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
            }
        })
    {
        process.OutputDataReceived += (sender, args) => Display(args.Data);
        process.ErrorDataReceived += (sender, args) => Display(args.Data);

        process.Start();
        process.BeginOutputReadLine();
        process.BeginErrorReadLine();

        process.WaitForExit(); //you need this in order to flush the output buffer
    }   
}

void Display(string output)
{
    _syncContext.Post(_ => myTextBox.AppendText(output), null);
}
like image 87
Ohad Schneider Avatar answered Oct 19 '22 21:10

Ohad Schneider


The MSDN article states:

The redirected StandardError stream can be read synchronously or asynchronously. Methods such as Read, ReadLine, and ReadToEnd perform synchronous read operations on the error output stream of the process. These synchronous read operations do not complete until the associated Process writes to its StandardError stream, or closes the stream.

In contrast, BeginErrorReadLine starts asynchronous read operations on the StandardError stream. This method enables a designated event handler for the stream output and immediately returns to the caller, which can perform other work while the stream output is directed to the event handler.

Synchronous read operations introduce a dependency between the caller reading from the StandardError stream and the child process writing to that stream. These dependencies can result in deadlock conditions. When the caller reads from the redirected stream of a child process, it is dependent on the child. The caller waits on the read operation until the child writes to the stream or closes the stream. When the child process writes enough data to fill its redirected stream, it is dependent on the parent. The child process waits on the next write operation until the parent reads from the full stream or closes the stream. The deadlock condition results when the caller and child process wait on each other to complete an operation, and neither can proceed. You can avoid deadlocks by evaluating dependencies between the caller and child process.

The same applies to the StandardOutput, so you just read both streams asynchronously.

Merging both streams into one complicates detection of what output is the error reporting and what is the 'product' information.

like image 45
Serge Avatar answered Oct 19 '22 20:10

Serge


I found the answer:

The output streams are buffered. There is no way to get the true sequential order of the items inserted into the streams. In fact it makes little sense as both streams can be written too at the same time. They are independent of each other. Therefore the best you can do is get the sequential output from each one as they arrive.

Generally this is not an issue though as almost all console apps use standard output for both output and error messages. The error stream is used by some apps but the messages are generally duplicates of the errors generated in the output stream.

Source: http://social.msdn.microsoft.com/Forums/uk/csharpgeneral/thread/192b6df7-9437-42cf-81c1-c125021735ba

like image 3
Martin Vseticka Avatar answered Oct 19 '22 21:10

Martin Vseticka