PConsole.StartInfo.RedirectStandardOutput and pConsole.Exited event (C #)

I have a GUI application that runs (in a new process) console applications and parses the output. To redirect the output, I set pConsole.StartInfo.RedirectStandardOutput to true. I also subscribe to the pConsole.Exited event.

The problem that I see is that I have to use Thread.Sleep () in the Exited event handler to get the latest data.

My Exited event handler looks like this:

Thread.Sleep(100); // Wait for additional data (if any). pConsole.OutputDataReceived -= new System.Diagnostics.DataReceivedEventHandler(this.localTerminal_DataAvailableEvent); int exit = pConsole.ExitCode; pConsole.Dispose(); pConsole = null; 

It seems that the Exited event is fired before my last pConsole_DataAvailableEvent. Does anyone know how / why this happens?

I also use mutex / lock to complete my Exited event before I launch the next console application.

+3
c # process console
source share
4 answers

The problem almost certainly is output buffering: the process terminates by raising the Exited event, but some output is still in the buffer. Your hack will probably work in some cases, but other approaches may be more reliable. Consider:

1) Exclude the Exited event handler and instead check Process.HasExited in the OutputDataReceived handler.

2) Do not use the OutputDataReceived handler, but just ask Read () for the Process.StandardOutput stream. Clean after treatment after closing the stream.

+3
source share

I don't know if this is better, but I just watched something like this, using streams to read both stderr / stdout and below. It includes a few extra threads (to avoid deadlocks / complex asynchronous code), but it seems to work quite reliably.

The key here is that I Join() for two threads handling IO, so I only move once when both output streams are fully consumed.

  using (Process proc = Process.Start(psi)) { Thread stdErr = new Thread(DumpStream(proc.StandardError, Console.Error)); Thread stdOut = new Thread(DumpStream(proc.StandardOutput, Console.Out)); stdErr.Name = "stderr reader"; stdOut.Name = "stdout reader"; stdErr.Start(); stdOut.Start(); proc.WaitForExit(); stdOut.Join(); stdErr.Join(); if (proc.ExitCode != 0) {...} // etc } static ThreadStart DumpStream(TextReader reader, TextWriter writer) { return (ThreadStart) delegate { string line; while ((line = reader.ReadLine()) != null) writer.WriteLine(line); }; } 
+2
source share

I strongly suspect that this is just an operating system that clears any output buffers. It looks like your workaround is okay, although obviously it is ugly (not your mistake), and the duration of sleep can be wastefully long in some cases and not long enough in some pathological other cases.

+1
source share

In addition to Mark Gravell's answer

proc.StandardError, proc.StandardOutput have an EndOfStream method. This will be useful for determining when the output does not give a new line before user input / query.

0
source share

All Articles