Правильный способ обработки стандартной ошибки и вывод из программы при порождении через класс процесса из C #? - PullRequest
7 голосов
/ 09 ноября 2010

Я прочитал документацию для Process.StandardOutput , в которой есть эта цитата:

Условие взаимоблокировки может возникнуть, если родительский процесс вызывает p.WaitForExit перед p.StandardOutput.ReadToEnd и дочерний процесс записывает достаточно текста для заполнения перенаправленного потока.

Так что мне интересно. Как правильно сделать это, если я также боюсь, что StandardError может быть заполнено в некоторых сценариях?

Должен ли я использовать цикл для чередования чтения из стандартного вывода и ошибки, чтобы избежать либо заполнения, либо этого простого кода достаточно:

string error = proc.StandardError.ReadToEnd();
string output = proc.StandardOutput.ReadToEnd();
bool didFinish = proc.WaitForExit(60000);

Отредактировано после публикации некоторых ответов

Так что это правильный подход?

var output = new StringBuilder();
proc.OutputDataReceived += (s, e) => output.Append(e.Data);
proc.BeginOutputReadLine();
string error = proc.StandardError.ReadToEnd();
bool didFinish = proc.WaitForExit(60000);

И тогда я использую контент stringbuilder, только если процесс действительно завершен.

Тогда это правильный подход?

Ответы [ 2 ]

7 голосов
/ 09 ноября 2010

Ваш пример кода может вызвать тупиковую ситуацию, когда что-то было записано в StandardOutput, а не в StandardError.Самый следующий пример из документации, которую вы связали, так же гласит:

По сути, я бы порекомендовал использовать асинхронные операции чтения в обоих потоках для заполнения буфера при записи в потоки, а затем вызвать * 1005.*.

3 голосов
/ 09 ноября 2010

Проблема возникает из-за того, что дочерний процесс записывает свой стандартный вывод и стандартную ошибку в пару каналов, которым ОС предоставляет конечный буфер.Если родитель не читает их активно, они могут заполниться.Когда канал заполняется, все последующие записи в него блокируются.

В вашем примере вы читаете все StandardError, а затем все StandardOutput.Это работает нормально, если дочерний процесс записывает только немного данных в StandardError и / или StandardOutput.Это проблема, если дочерний процесс хочет записать много данных в StandardOutput.Пока родительский процесс ожидает получения данных из StandardError, дочерний процесс занят заполнением буфера StandardOutput.

Самый безопасный способ - это одновременное чтение из стандартной ошибки и стандартной ошибки.Есть несколько способов сделать это:

  • Создать отдельные потоки и вызвать ReadToEnd на каждом
  • Использовать BeginRead и EndRead на одном потоке
  • Добавьте обработчики для событий Process.ErrorDataReceived и Process.OutputDataReceived, затем вызовите Process.BeginErrorReadLine и Process.BeginOutputReadLine.
...