Взаимоблокировка при выходе / буфер ошибок

#c# #.net

#c# #.net

Вопрос:

Вот код:

 var output = new StringWriter();
var error = new StringWriter();

var p = new Process();
p.StartInfo = new ProcessStartInfo
{
    WorkingDirectory = workingDir,
    FileName = file,
    Arguments = args,
    UseShellExecute = false,
    RedirectStandardOutput = true,
    RedirectStandardError = true,
};
p.OutputDataReceived  = (o, e) => { output.WriteLine(e.Data); };
p.ErrorDataReceived  = (o, e) => { error.WriteLine(e.Data); };

p.Start();

if (!p.WaitForExit((int)timeout.TotalMilliseconds))
{
    p.Kill();
    throw new Exception("Timeout expired.");
}

string errorData = error.ToString();
if (errorData.Length > 0)
    throw new Exception(errorData);

return output.ToString();
 

Я бы ожидал OutputDataReceived , ErrorDataReceived что обработчики and будут вызываться всякий раз, когда данные становятся доступными, однако этого не происходит. Для процесса, который выводит тонну материала в стандартный вывод, этот код в конечном итоге завершается throw new Exception("Timeout expired."); . Я попытался добавить некоторый отладочный код в обработчики, но он никогда не вызывается. Разве весь смысл указания обработчиков out / err не в том, чтобы вызывать их асинхронно?

Ответ №1:

Из документации:

Событие активируется во время асинхронных операций чтения при стандартном выводе. Чтобы запустить асинхронные операции чтения, вы должны перенаправить поток стандартного вывода процесса, добавить свой обработчик событий в событие OutputDataReceived и вызвать BeginOutputReadLine . После этого событие OutputDataReceived сигнализирует каждый раз, когда процесс записывает строку в перенаправленный поток StandardOutput, пока процесс не завершится или не вызовет CancelOutputRead .

Вы не выполняете никаких асинхронных операций чтения, поэтому событие не будет запущено.

Если вы просто добавите вызов p.BeginOutputReadline() после запуска процесса, он будет работать. Аналогично, чтобы прочитать поток ошибок, вызовите BeginErrorReadLine() .

Ответ №2:

Чтобы начать получать события из стандартного вывода и стандартной ошибки, вам нужно вызвать BeginOutputReadLine() и BeginErrorReadLine() , соответственно.