views:

1503

answers:

4

Hi,

I have a GUI application that executes (in a new process) "console" applications and parse the output. To redirect the Output i set the pConsole.StartInfo.RedirectStandardOutput to true. I also subscribes to the event pConsole.Exited.

The problem I see is that I have to use Thread.Sleep() in the Exited event handler to get the last 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 executes before my last pConsole_DataAvailableEvent. Anyone knows how/why this is happening?

I also use a mutex/lock to make sure my Exited event is finished before I start execute my next console application.

A: 

I strongly suspect that it's just the operating system flushing any output buffers. It looks like your workaround is okay-ish, although obviously it's ugly (not your fault) and the length of sleep could be wastefully long in some cases and not long enough in some pathological other cases.

Jon Skeet
+2  A: 

I don't know if it is any better, but I've just been looking at something similar using threads to read both stderr/stdout, like below. It involves a few extra threads (to avoid deadlocks / complex async code), but seems to work pretty robustly.

The key here is that I Join() on the two threads handling IO, so I only move on once both output streams have been 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);
         };
    }
Marc Gravell
This solution works with .NET 1.1, too. Some of us still have to maintain legacy code.
gyrolf
+2  A: 

The problem is almost certainly output buffering: the process exits, triggering your Exited event, but some output data is still in the buffer. Your hack will probably work in some cases, but other approaches may be more robust. Consider:

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

2) Don't use the OutputDataReceived handler, but simply have a call Read() on the Process.StandardOutput stream. Do the post-process cleanup once the stream is closed.

JSBangs
Suggestion 1) was the accepted answer.
TToni
A: 

Thanks for your suggestions. I did revisited my code and implemented the first suggestion from JS Bangs. The code/application work allot better now, and it looks more nicely...So thanks again all!

You should upvote the answer that you used, and also probably mark it as the accepted answer.
JSBangs