Sein über ein Jahr seit dem letzten Mal ich blogging. Tut mir leid, aber es war ein sehr anstrengendes Jahr. Ive beschlossen, wieder abzuholen und versuchen, einige tech-bezogene zufällige Gedanken einmal in eine Weile. Heute wollte ich nur einen Bug teilen, den ich gefunden habe, der für einige von Euch interessant sein könnte. Ich hatte eine kleine Funktion, die einen Prozess gestartet und wartete, bis es seine Arbeit zu beenden. Der Code sah so aus: Process P new Process () P. StartInfo. UseShellExecute false P. StartInfo. RedirectStandardOutput true P. StartInfo. RedirectStandardError true P. StartInfo. FileName pathToProgramm P. StartInfo. Arguments programArguments P. Start () P. WaitForExit () P. Close () Da der Prozess manchmal dauert eine Weile zu beenden, wollte ich in der Lage sein zu sehen, was los war, so entschied ich, von stderrstdinput lesen, um zu sehen, wenn etwas schief gelaufen. Um dies zu tun, stellte ich sicher, dass die RedirectStandardError-Eigenschaften des Prozesses auf true (siehe Code oben) gesetzt wurde, und fügte die folgende Zeile ein, um zu überprüfen, ob die Anwendung auf irgendwelche Fehler gestoßen war: P. WaitForExit () string err P. StandardError. ReadToEnd () P. Close () Nachdem dieser Code für eine Weile verwendet wurde, bemerkte ich, dass einmal in eine Weile die Anwendung hing, wenn die oben genannten Prozess. Das Problem trat nur auf, wenn viele Daten in standarderror geschrieben wurden. Ich debugging das Problem, und festgestellt, dass weglassen Lesung von StandardError entfernt das Problem. Ich dachte, dass dies wie ein seltsames Problem schien und fuhr fort, nach einer Lösung zu suchen. Nach dem Lesen der Dokumentation, kam ich endlich mit den Informationen, die das Problem aufgedeckt. Die folgende Anmerkung in der msdn-Bibliothek für die RedirectStandardError-Eigenschaft sagt: Die Process-Komponente kommuniziert mit einem untergeordneten Prozess mithilfe einer Pipe. Wenn ein untergeordneter Prozess genug Daten an die Pipe schreibt, um den Puffer zu füllen, wird das Kind blockieren, bis das übergeordnete Element die Daten aus der Pipe liest. Dies kann zu einem Deadlock führen, wenn Ihre Anwendung alle Ausgabe auf Standardfehler und Standardausgabe liest, z. B. unter Verwendung des folgenden C-Codes. Also, anstatt den Prozess zu bitten, den Puffer zu füllen und darauf zu warten, dass ich ihn leere, damit der Aufruf von WaitForExit () blockiert würde, las der Inhalt des Puffers (P. StandardError. ReadToEnd ()), bevor WaitForExit () aufgelöst wurde Problem und machte die Lösung zum Erfolg. Fazit: Lesen Sie die Dokumentation. Und stellen Sie sicher, dass Sie die Bemerkungen lesen. Der Code sieht fast so aus: Wie Sie sehen können, startet der Code ein cmd. exe-Prozess und übergibt 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 seine empfohlen, um umgeleitete Ströme vor dem Prozess lesen. WaitForExit (Timeout) Aufruf, auch das ist besonders wahr, 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 dies kann passieren, weil der Code hängt Die Linie mit Prozess. WaitForExit (), die immer warten wird, bis das untergeordnete Projekt beendet wird. Die Standardgröße für beide 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 Schreiben Sie 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 die cmd. exe Prozess und seine möglichen Kinder zu töten.
No comments:
Post a Comment