我有一个GUI应用程序,它(在一个新进程中)执行“控制台”应用程序并解析输出。为了重定向输出,我将pConsole.StartInfo.RedirectStandardOutput设置为true。我还订阅了event pConsole.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;
退出的事件似乎在我的最后一个pConsole_DataAvailableEvent之前执行。有人知道这是怎么发生的吗?
在开始执行下一个控制台应用程序之前,我还使用了互斥锁/锁来确保退出的事件已经完成。
发布于 2008-11-03 18:06:58
问题几乎肯定是输出缓冲:进程退出,触发您退出的事件,但一些输出数据仍在缓冲区中。您的hack在某些情况下可能会起作用,但其他方法可能更健壮。考虑一下:
1)删除已退出的事件处理程序,改为检查OutputDataReceived处理程序中的Process.HasExited。
2)不要使用OutputDataReceived处理程序,只需在Process.StandardOutput流上调用Read()即可。在流关闭后执行处理后清理。
发布于 2008-11-03 11:31:57
我不知道它是不是更好,但我只是在看一些类似的东西,使用线程来读取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);
};
}
发布于 2008-11-03 11:09:45
我强烈怀疑这只是操作系统刷新所有输出缓冲区。看起来你的解决办法还可以,尽管它显然很丑陋(不是你的错),而且在某些情况下睡眠时间可能会过长,而在某些病态的其他情况下睡眠时间可能不够长。
https://stackoverflow.com/questions/258339
复制相似问题