PConsole.StartInfo.RedirectStandardOutput и событие pConsole.Exited (C#)

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
2 373
4

Ответы 4

Я сильно подозреваю, что это всего лишь операционная система, очищающая все выходные буферы. Похоже, ваш обходной путь в порядке, хотя, очевидно, он уродлив (не ваша вина), и продолжительность сна может быть расточительно долгой в некоторых случаях и недостаточной в некоторых других патологических случаях.

Я не знаю, лучше ли это, но я только что искал что-то подобное, используя потоки для чтения как 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);
         };
    }

Это решение также работает с .NET 1.1. Некоторым из нас все еще приходится поддерживать унаследованный код.

gyrolf 04.02.2009 09:39

Проблема почти наверняка заключается в буферизации вывода: процесс завершается, вызывая событие Exited, но некоторые выходные данные все еще находятся в буфере. Ваш взлом, вероятно, сработает в некоторых случаях, но другие подходы могут быть более надежными. Рассматривать:

1) Устранение обработчика событий Exited и вместо этого отметьте Process.HasExited в обработчике OutputDataReceived.

2) Не используйте обработчик OutputDataReceived, а просто вызовите Read () в потоке Process.StandardOutput. После закрытия потока выполните очистку постобработки.

В дополнение к ответу Марка Гравелла

proc.StandardError, proc.StandardOutput оба имеют метод EndOfStream. Это будет полезно для определения случая, когда на выходе не отображается новая строка перед вводом / запросами пользователя.

Другие вопросы по теме