pConsole.StartInfo.RedirectStandardOutput和pConsole.Exited事件(c#)

时间:2022-10-18 20:45:13

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.

我有一个GUI应用程序执行(在一个新的进程中)“控制台”应用程序并解析输出。要重定向输出,请将pConsole.StartInfo.RedirectStandardOutput设置为true。我还订阅了pConsole.Exited事件。

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

我看到的问题是我必须在Exited事件处理程序中使用Thread.Sleep()来获取最后的数据。

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?

似乎Exited事件在我的上一个pConsole_DataAvailableEvent之前执行。任何人都知道这是怎么回事?

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

在开始执行下一个控制台应用程序之前,我还使用互斥锁/锁来确保我的Exited事件已完成。

4 个解决方案

#1


3  

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.

1)消除Exited事件处理程序,而是检查OutputDataReceived处理程序中的Process.HasExited。

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.

2)不要使用OutputDataReceived处理程序,而只是在Process.StandardOutput流上调用Read()。关闭流后进行后处理清理。

#2


2  

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.

我不知道它是否更好,但我一直在寻找类似的东西,使用线程来读取stderr / stdout,如下所示。它涉及一些额外的线程(以避免死锁/复杂的异步代码),但似乎非常健壮。

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.

这里的关键是我在处理IO的两个线程上加入(),所以我只在两个输出流都被完全消耗后才继续运行。

            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);
         };
    }

#3


1  

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.

我强烈怀疑它只是操作系统刷新任何输出缓冲区。看起来你的解决方法是好的,虽然显然它很难看(不是你的错),在某些情况下,睡眠时间可能浪费很长,而在某些其他情况下也不够长。

#4


0  

In addition to Marc Gravell's answer

除了Marc Gravell的回答

proc.StandardError, proc.StandardOutput both has a EndOfStream method. This will be useful to determine the case where the output does not yield a newline before user inputs/prompts

proc.StandardError,proc.StandardOutput都有一个EndOfStream方法。这将有助于确定输出在用户输入/提示之前不产生换行的情况

#1


3  

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.

1)消除Exited事件处理程序,而是检查OutputDataReceived处理程序中的Process.HasExited。

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.

2)不要使用OutputDataReceived处理程序,而只是在Process.StandardOutput流上调用Read()。关闭流后进行后处理清理。

#2


2  

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.

我不知道它是否更好,但我一直在寻找类似的东西,使用线程来读取stderr / stdout,如下所示。它涉及一些额外的线程(以避免死锁/复杂的异步代码),但似乎非常健壮。

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.

这里的关键是我在处理IO的两个线程上加入(),所以我只在两个输出流都被完全消耗后才继续运行。

            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);
         };
    }

#3


1  

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.

我强烈怀疑它只是操作系统刷新任何输出缓冲区。看起来你的解决方法是好的,虽然显然它很难看(不是你的错),在某些情况下,睡眠时间可能浪费很长,而在某些其他情况下也不够长。

#4


0  

In addition to Marc Gravell's answer

除了Marc Gravell的回答

proc.StandardError, proc.StandardOutput both has a EndOfStream method. This will be useful to determine the case where the output does not yield a newline before user inputs/prompts

proc.StandardError,proc.StandardOutput都有一个EndOfStream方法。这将有助于确定输出在用户输入/提示之前不产生换行的情况