Friday 6 October 2017

Waitforexit Hangsim


Ich benutze Process. Start, um eine Batchdatei zu starten. Die Batchdatei verwendet den START-Befehl, um mehrere Programme parallel zu starten und dann zu beenden. Sobald die Batchdatei fertig ist, wird Process. HasExited wahr und Process. ExitCode enthält den korrekten Exit-Code. Aber wenn ich Process. WaitForExit () aufrufen, hängt / nie zurück. Das folgende Codebeispiel zeigt das Problem. Es erstellt eine Batch-Datei, startet es und druckt dann: Es sollte dann drucken: aber es funktioniert nie (obwohl HasExited ist wahr und wir haben bereits einen ExitCode). Ich bemerkte, dass dies nur geschieht, wenn die Batch-Datei START-Befehle enthält und wenn Standardausgabe und / oder Standardfehler umgeleitet werden. Warum hat WaitForExit () nie wieder Was ist der richtige Weg zu warten, für einen solchen Prozess zu beenden Ist es sicher, nur Abfrage Process. HasExited oder kann das Ergebnis in anderen Problemen PS. Ich habe gerade festgestellt, dass das Aufrufen von WaitForExit (100000) mit einem riesigen Timeout (das definitiv nicht abläuft) sofort zurück, wenn der Prozess beendet wird. Wierd. Ohne Timeout hängt es. Es gibt einen grundlegenden Unterschied, wenn Sie WaitForExit () ohne ein Timeout aufrufen, es stellt sicher, dass die umgeleiteten stdout / err EOF zurückgegeben haben. Dieses stellt sicher, dass you39ve alle Ausgabe lesen, die durch den Prozess produziert wurde. Wir können nicht sehen, was quotonOutputquot tut, aber hohe Chancen, dass es Deadlocks Ihr Programm, weil es etwas Bösartiges wie die Annahme, dass Ihr Haupt-Thread im Leerlauf ist, wenn es tatsächlich in WaitForExit () stecken tut. Ndash Hans Passant Nov 3 14 am 12:06 Das scheint ein Artefakt zu sein (Id say bug) in der spezifischen Implementierung der ereignisbasierten asynchronen Handhabung von StandardOutput und StandardError. Ich bemerkte, dass, während ich konnte leicht reproduzieren Sie Ihr Problem, indem Sie einfach den Code, den Sie zur Verfügung gestellt (exzellent Code-Beispiel, übrigens)), hielt der Prozess nicht wirklich unbegrenzt. Vielmehr kehrte es von WaitForExit () zurück, nachdem beide der untergeordneten Prozesse selbst gestartet waren. Dies scheint ein absichtlicher Teil der Implementierung der Process-Klasse zu sein. Insbesondere überprüft es in der Process. WaitForExit () - Methode, sobald es das Warten auf den Prozess-Handle selbst beendet hat, ob ein Leser für stdout oder stderr erstellt wurde, falls dies der Fall ist und wenn der Timeoutwert für die WaitForExit ( ) Aufruf ist unendlich (dh -1), der Code wartet tatsächlich auf den End-of-Stream auf den Leser (n). Jeder entsprechende Leser wird nur erstellt, wenn die Methode BeginOutputReadLine () oder BeginErrorReadLine () aufgerufen wird. Die Stdout - und Stderr-Ströme werden erst nach dem Schließen der Kinderprozesse geschlossen. So warten auf das Ende dieser Ströme wird blockiert, bis das geschieht. Das WaitForExit () sollte sich anders verhalten, je nachdem, ob man eine der Methoden aufgerufen hat, die das ereignisbasierte Lesen der Streams starten oder nicht, und vor allem, dass das Lesen dieser Streams direkt nicht dazu führt, dass WaitForExit () sich so verhält Eine Inkonsistenz in der API, die es viel schwieriger zu verstehen und zu verwenden macht. Während Id persönlich nennen dies einen Bug, ich vermute, seine mögliche, dass die implementor (s) der Process-Klasse sind sich dieser Inkonsistenz bewusst und schuf sie mit Absicht. In jedem Fall wäre das Work-around zu lesen StandardOutput und StandardError direkt statt der Verwendung der ereignisbasierten Teil der API. (Natürlich, wenn diejenigen Code auf diesen Streams warten, würde man das gleiche Blocking-Verhalten zu sehen, bis das Kind Prozesse schließen.) Zum Beispiel (C, weil ich nicht wissen, F gut genug, um ein Codebeispiel wie diese zusammen schnell schlagen :)): Hoffentlich wird die oben genannten Work-around oder etwas ähnliches auf die grundlegende Frage Sie in laufen. Ich danke dem Kommentator Niels Vorgaard Christensen, der mich an die problematischen Linien in der WaitForExit () - Methode weiterleitet, damit ich diese Antwort verbessern kann. Der Code sieht fast so aus: Wie Sie sehen können, startet der Code einen cmd. exe Prozess und Übergibt ihm den Befehl, den ich ausführen möchte. Ich umleiten StandardError und StandarOutput, um sie aus dem Code zu lesen. Der Code liest sie vor dem Prozess. WaitForExit (Timeout), wie von Microsoft empfohlen (mehr dazu später). Das Problem tritt auf, wenn der Befehl, den ich an cmd. exe sendet, niemals endet oder hängt unbegrenzt. Im Code verwendete ich den Befehl ping - t 8.8.8.8, der wegen der Option - t den Host ohne Stopp pingt. Was passiert Der Befehl cmd. exe zusammen mit dem Befehl ping - txt wird nie beendet und der Stdout-Stream wird nie geschlossen, und daher hängt unser Code an der Ausgabe process. StandardOutput. ReadToEnd () Zeile, weil es nicht gelingt, den gesamten Stream zu lesen. Das gleiche passiert auch, wenn ein Befehl in einer Batch-Datei aus irgendeinem Grund hängt und so der obige Code könnte kontinuierlich arbeiten für Jahre und dann hängen plötzlich ohne ersichtlichen Grund. Bevor ich schrieb, dass es empfohlen, um umgeleitete Streams vor dem Prozess lesen. WaitForExit (Timeout) Aufruf, auch dies gilt insbesondere, wenn Sie die WaitForExit Signatur ohne das Timeout verwenden. Wenn Sie Prozess aufrufen. WaitForExit (), bevor Sie die umgeleiteten Datenströme lesen: code 2: Sie können einen Deadlock erleben, wenn der Befehl, den Sie an cmd. exe anhängen, oder der Prozess, den Sie aufrufen, die Standardausgabe oder Standardfehler erfüllt. Dies, weil unsere Code cant erreichen die Linien Output-Prozess. Standardausgang. ReadToEnd () In der Tat der Kind-Prozess (die Ping-Befehl oder eine Batch-Datei oder was auch immer Sie ausführen) cant gehen auf, wenn unser Programm nicht lesen Sie die gefüllten Puffer der Streams und diese Cant passieren, weil der Code hängt Die Linie mit Prozess. WaitForExit (), die immer warten wird, bis das untergeordnete Projekt beendet wird. Die Standardgröße beider Streams beträgt 4096 Byte. Sie können diese beiden Größen mit diesen Batchdateien testen: Das erste Skript schreibt 4096 Byte zur Standardausgabe und das zweite zu Standardfehler. Speichern Sie eine davon in C: testbuffsize. bat und führen Sie unseren Programmaufruf aus. WaitForExit () vor Ausgabeprozess. Standardausgang. ReadToEnd () wie in Code 2. Können Sie es Schreiben CommandResult Ergebnis ExecuteShellCommandSync (c: testbuffsize. bat, 1000) in Zeile 13 von Code 1. Der Code wird nicht hängen, aber wenn Sie schreiben ein weiteres Byte in einem der beiden Streams wird es überlaufen die Puffergröße, die das Programm aufhängen. Wenn Sie die Standardausgabe oder Standardfehler umleiten und lesen müssen, ist die beste Lösung, sie asynchron zu lesen. Eine hervorragende Möglichkeit, dies zu tun, wird von Mark Byers in diesem Stackoverflow-Thread vorgeschlagen Als das letzte, beachten Sie bitte, dass, wenn der untergeordnete Prozess beendet, nur weil Sie den Prozess verwenden. WaitForExit (Timeout) Signatur und es tatsächlich geht in Timeout sollten Sie den Prozess cmd. exe und seine möglichen Kinder töten. Ihre Lösung braucht nicht AutoResetEvent aber Sie Umfrage. Wenn Sie die Umfrage statt der Verwendung von Event (wenn sie verfügbar sind), dann sind Sie mit CPU ohne Grund und dass zeigen, dass Sie ein schlechter Programmierer sind. Ihre Lösung ist wirklich schlecht, wenn die anderen mit AutoResetEvent verglichen werden. (Aber ich habe dir nicht gegeben -1, weil du versucht hast zu helfen). Ndash Eric Ouellet 7. November um 18:38 Ich hatte das gleiche Problem, aber der Grund war anders. Es würde jedoch unter Windows 8, aber nicht unter Windows 7 auftreten. Die folgende Zeile scheint das Problem verursacht haben. Die Lösung war NICHT deaktivieren UseShellExecute. Ich erhielt nun ein Shell-Popup-Fenster, das unerwünscht ist, aber viel besser als das Programm wartet auf nichts Besonderes passieren. So fügte ich die folgende Arbeit-um für das hinzu: Jetzt das einzige, das mich stört, ist, warum dieses geschieht unter Windows 8 an erster Stelle. Beantwortet Jan 13 15 am 10:35 Anwendungsbeispiel Umsetzung

No comments:

Post a Comment