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

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

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

我的退出事件处理程序如下所示:

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; 

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

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

问题几乎肯定是输出缓冲:进程退出,触发退出事件,但某些输出数据仍在缓冲区中。 你的黑客可能会在某些情况下工作,但其他方法可能更强大。 考虑:

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

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

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

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

  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的回答

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