7

las ich die Dokumentation für Process.StandardOutput, die dieses Zitat hat:Korrekter Weg, um Standardfehler zu behandeln und von einem Programm auszugeben, wenn es über die Prozessklasse von C# erzeugt wurde?

Ein Deadlock führen kann, wenn der übergeordnete Prozess p.WaitForExit vor p.StandardOutput.ReadToEnd und das Kind Prozess schreibt genug Text fordert die umgeleitet zu füllen Strom.

Also ich frage mich. Was ist der richtige Weg dies zu tun, wenn ich auch Angst habe, dass StandardError in einigen Szenarien erfüllt werden könnte?

Muss ich eine Schleife verwenden, um von der Standardausgabe und Fehler zu wechseln Lesen, entweder bis zu vermeiden Füllung oder ist dieser einfache Code genug:

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

Herausgegeben nach ein paar Antworten haben gepostet

Also das ist der richtige Ansatz?

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

Und dann verwende ich den Stringbuilder-Inhalt nur, wenn der Prozess tatsächlich abgeschlossen ist.

Ist das der richtige Ansatz?

+0

Überprüfen Sie die Antwort http: // stackoverflow.com/a/7608823/276648 – user276648

Antwort

6

Ihr Beispielcode könnte ein Deadlock situtation führen, wo es etwas geschrieben an die StandardOutput und nicht zu StandardError war. Das nächste Beispiel aus der Dokumentation, die Sie verlinkt haben, gibt das genauso an.

Im Wesentlichen, was ich empfehlen würde, ist die Async-Lesevorgänge in beiden Streams, um einen Puffer zu füllen, wie die Streams geschrieben werden, und rufen Sie dann WaitForExit.

+0

Ja, ich bin neugierig, warum Sie nicht nur diese Methode verwenden, wie in der MSDN angegeben 'Sie können asynchrone Lesevorgänge verwenden, um diese Abhängigkeiten und ihr Deadlock-Potenzial zu vermeiden. Alternativ können Sie die Deadlock-Bedingung vermeiden, indem Sie zwei Threads erstellen und die Ausgabe jedes Streams in einem separaten Thread lesen. " – jcolebrand

+0

In Code mit BeginOutputReadLine und OutputDataReceived bearbeitet, können Sie einen Blick darauf werfen, ob der angegebene Code korrekt ist? –

+0

Das ist, was ich mit endete: http://bitbucket.org/lassevk/mercurial.net/src/728f85d67447/Mercurial.Net/ClientWrapper.cs#cl-111 –

3

Das Problem tritt auf, weil der untergeordnete Prozess seine Standardausgabe und seinen Standardfehler in ein Paar von Pipes schreibt, die vom Betriebssystem einen endlichen Puffer erhalten. Wenn der Elternteil beide nicht aktiv liest, sind sie wahrscheinlich voll. Wenn eine Pipe voll ist, werden alle nachfolgenden Schreibvorgänge blockiert.

In Ihrem Beispiel lesen Sie alle StandardError dann alle StandardOutput. Dies funktioniert, wenn der untergeordnete Prozess nur ein wenig Daten in StandardError und/oder StandardOutput schreibt. Es ist ein Problem, wenn der untergeordnete Prozess viele Daten in StandardOutput schreiben möchte. Während der übergeordnete Prozess darauf wartet, Daten von StandardError zu verbrauchen, füllt der untergeordnete Prozess den Puffer StandardOutput.

Der sicherste Weg ist das gleichzeitige Lesen von Standard- und Standardfehlern. Es gibt ein paar Möglichkeiten, dies zu tun:

  • Spawn separate Threads und rufen ReadToEnd auf jedes
  • Verwenden BeginRead und EndRead auf einem Thread
  • hinzufügen Handler auf den Process.ErrorDataReceived und Process.OutputDataReceived Ereignisse, dann rufen Process.BeginErrorReadLine und Process.BeginOutputReadLine.
Verwandte Themen