Process.WaitForExit wird nicht zurückgegeben, obwohl Process.HasExited true ist

8

Ich benutze Process.Start, um eine Batch-Datei zu starten. Die Stapeldatei verwendet den Befehl "START", um mehrere Programme parallel zu starten und wird dann beendet.

Sobald die Batch-Datei fertig ist, wird Process.HasExited wahr und Process.ExitCode enthält den korrekten Exit-Code.

Aber wenn ich Process.WaitForExit () aufrufe, bleibt es hängen / kehrt nie zurück.

Der folgende Codeabschnitt veranschaulicht das Problem. Es erstellt eine Batch-Datei, startet sie und druckt dann:

%Vor%

Es sollte dann drucken:

%Vor%

... tut es aber nie (obwohl HasExited wahr ist und wir bereits einen ExitCode haben).

%Vor%

Ich habe bemerkt, dass dies nur passiert, wenn die Batch-Datei "START" -Befehle enthält und wenn Standardausgabe und / oder Standardfehler umgeleitet werden.

Warum kehrt WaitForExit () nie zurück?

Was ist die richtige Art zu warten, bis ein solcher Prozess beendet wird?

Ist es sicher, nur Process.HasExited abzufragen, oder kann dies zu anderen Problemen führen?

PS .: Ich habe gerade bemerkt, dass das Aufrufen von WaitForExit ( 100000 ) mit einem großen Timeout (das definitiv nicht abläuft) sofort zurückkehrt, wenn der Prozess beendet wird. Sonderbar. Ohne Zeitüberschreitung hängt es.

    
stmax 03.11.2014, 11:32
quelle

1 Antwort

16

Dies scheint ein Artefakt (ich würde sagen "Bug") in der spezifischen Implementierung der ereignisbasierten asynchronen Behandlung von StandardOutput und StandardError zu sein.

Ich habe bemerkt, dass ich zwar Ihr Problem einfach reproduzieren konnte, indem ich einfach den Code ausführte, den Sie mir zur Verfügung gestellt hatten (übrigens ein exzellentes Codebeispiel! :)), der Prozess war jedoch nicht unendlich lang. Es wurde vielmehr von WaitForExit () zurückgegeben, sobald beide untergeordneten Prozesse, die gestartet wurden, selbst beendet wurden.

Dies scheint ein intentionaler Teil der Implementierung der Process -Klasse zu sein. Insbesondere in der Process.WaitForExit() -Methode, sobald dies der Fall ist fertig warten auf den Prozess handle selbst, es überprüft, ob ein Reader für entweder stdout oder stderr erstellt wurde; Wenn dies der Fall ist und der Zeitüberschreitungswert für den WaitForExit() -Aufruf "unendlich" ist (d. h. -1 ), wartet der Code tatsächlich auf das Ende des Streams auf den Lesern.

Jeder entsprechende Leser wird nur erstellt, wenn die Methode BeginOutputReadLine() oder BeginErrorReadLine() aufgerufen wird. Die Stdout- und Stderr-Streams werden selbst erst geschlossen, wenn die Child-Prozesse abgeschlossen sind. Also wird das Warten auf das Ende dieser Ströme blockieren, bis das passiert.

Das WaitForExit() sollte sich unterschiedlich verhalten, abhängig davon, ob man eine der Methoden aufgerufen hat, die das ereignisbasierte Lesen der Streams starten oder nicht, und insbesondere, dass das Lesen dieser Streams direkt nicht ist Weil WaitForExit() sich so verhält, entsteht eine Inkonsistenz in der API, die es viel schwieriger zu verstehen und zu benutzen macht. Obwohl ich dies persönlich als Bug bezeichnen würde, ist es möglich, dass die Implementierer der Klasse Process diese Inkonsistenz kennen und absichtlich erstellt haben.

In jedem Fall besteht die Umgehung darin, StandardOutput und StandardError direkt zu lesen, anstatt den ereignisbasierten Teil der API zu verwenden. (Wenn natürlich der Code auf diese Streams wartet, würde man das gleiche Blockierungsverhalten sehen, bis die untergeordneten Prozesse schließen.)

Zum Beispiel (C #, weil ich F # nicht gut genug kenne, um ein Codebeispiel wie dieses schnell zusammen zu schlagen :)):

%Vor%

Hoffentlich wird das obige Problem oder etwas Ähnliches das Grundproblem lösen, mit dem Sie konfrontiert wurden. Mein Dank geht an commenter Niels Vorgaard Christensen , weil er mich zu den problematischen Linien in der Methode WaitForExit() geführt hat, damit ich diese Antwort verbessern konnte.

    
Peter Duniho 03.11.2014, 20:24
quelle

Tags und Links