У меня есть приложение с графическим интерфейсом, которое выполняет (в новом процессе) «консольные» приложения и анализирует вывод. Чтобы перенаправить вывод, я установил для pConsole.StartInfo.RedirectStandardOutput значение true. Я также подписываюсь на событие pConsole.Exited.
Проблема, которую я вижу, заключается в том, что мне нужно использовать Thread.Sleep () в обработчике событий Exited, чтобы получить последние данные.
Мой обработчик событий Exited выглядит так:
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 завершено, прежде чем я начну выполнять свое следующее консольное приложение.





Я сильно подозреваю, что это всего лишь операционная система, очищающая все выходные буферы. Похоже, ваш обходной путь в порядке, хотя, очевидно, он уродлив (не ваша вина), и продолжительность сна может быть расточительно долгой в некоторых случаях и недостаточной в некоторых других патологических случаях.
Я не знаю, лучше ли это, но я только что искал что-то подобное, используя потоки для чтения как stderr / stdout, как показано ниже. Он включает в себя несколько дополнительных потоков (чтобы избежать взаимоблокировок / сложного асинхронного кода), но, похоже, работает довольно надежно.
Ключевым моментом здесь является то, что я использую 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);
};
}
Проблема почти наверняка заключается в буферизации вывода: процесс завершается, вызывая событие Exited, но некоторые выходные данные все еще находятся в буфере. Ваш взлом, вероятно, сработает в некоторых случаях, но другие подходы могут быть более надежными. Рассматривать:
1) Устранение обработчика событий Exited и вместо этого отметьте Process.HasExited в обработчике OutputDataReceived.
2) Не используйте обработчик OutputDataReceived, а просто вызовите Read () в потоке Process.StandardOutput. После закрытия потока выполните очистку постобработки.
В дополнение к ответу Марка Гравелла
proc.StandardError, proc.StandardOutput оба имеют метод EndOfStream. Это будет полезно для определения случая, когда на выходе не отображается новая строка перед вводом / запросами пользователя.
Это решение также работает с .NET 1.1. Некоторым из нас все еще приходится поддерживать унаследованный код.