Friday, 20 October 2017

Ausgezeichnetes Wartezeit


NET System. Diagnostics. Process Klasse 8211 Teil 1 Process. WaitForExit und. Exited Veranstaltung aren8217t Arbeit Ich dachte, ich hatte festgestellt, dass dies der Fall, aber es war meine Schuld, wahrscheinlich das gleiche für Sie auch. Ich werde über das hinausgehen, was ich bei der Erforschung und Lösung dieses Problems gefunden habe. Kurzantwort: Wenn Sie StandardOutput und StandardError umleiten, verwenden Sie die asynchronen Process. BeginErrorReadLine () - und. BeginOutputReadLine () - Methoden vor dem Aufruf von. WaitForExit () und erfassen die Ausgabe, indem Sie die Process. ErrorDataReceived - und. OutputDataReceived-Ereignisse anhängen. Die lange Antwort beginnt mit mir mit dem Visual Studio diffmerge. exe im Common7IDE-Ordner, um Textdateien im Batch-Modus zu vergleichen. Ich stelle einen Regressionstest in einen Build-initiierten Batch-Prozess vor. Ich brauchte ein Werkzeug, das eine Textdifferenzdatei ausspucken würde, wenn man zwei Dateien vergleicht (nicht eine Zusammenführungsergebnisdatei). WinMerge und Beyond Compare sind zu meiner Verfügung, aber sie scheinen nicht produzieren alles, aber zusammengeführt Ergebnisse (was normalerweise ist was ich will, aber nicht dieses Mal). Mein Regressions-Framework ruft diffmerge. exe auf und speichert die resultierende Diff-Datei für eine spätere Überprüfung. Ich kodierte meine ProcessStartInfo Gefolgt, dass mit dem Auftakt aus dem Prozess und warten auf den Prozess zu beenden. Und warten warten warten Dies hat mich gelesen MSDN und graben tiefer in den Einsatz der Process-Klasse. Ich habe herausgefunden, einige interessante Informationen, wahrscheinlich hätte offensichtlich sein müssen. Zuerst habe ich festgestellt, dass manchmal läuft meine diffmerge Child Process mit verschiedenen Argumenten gearbeitet, manchmal es didnt, macht das Problem geheimnisvoll. Zweitens habe ich festgestellt, dass es gut funktioniert, als ich didn8217t umleiten Ausgabe. So fehlte mir natürlich etwas. Ich musste eigentlich die Prozess-API-Dokumente lesen, und so fand ich diesen Nugget: MSDN Artikel Nach dem Finden und Lesen, dass MSDN Artikel, den ich verstanden habe. Mein Codebeispiel oben funktioniert, wenn der StdOut - oder StdError-Puffer nicht füllt. Allerdings, was ich sah, war die StdOut-Pufferfüllung, der Child-Prozess wurde auf dem nächsten StdOutStdError-Schreiben blockiert, der Parent Process wartete unendlich auf den Child-Prozess, um vor dem Lesen aus dem StdOutStdError-Puffer zu beenden. Für mich schien es, dass WaitForExit Methode undor Exited Veranstaltung sind gebrochen nicht fangen die Kind Prozess verlassen, aber es war mein Code, der gebrochen war. Ich habe den Code geändert, um die asynchronen Methoden zu benutzen und plötzlich gingen meine Probleme weg. Nicht mehr blockiert, alles hat wie erwartet gearbeitet Ich habe StringBuilders als Puffer verwendet, um die in den Ereignissen empfangenen Daten zu halten. In Teil 2, ich laufe in ein Problem mit dem Process StdOutStdError ReadLine Implementierungen um meine spezifischen Bedürfnisse, gehe ich in, wie ich dieses Problem gelöst. System. Diagnostics. Process Klasse Teil 2 In Teil 1 diskutierte ich das Problem, wo mit Stdoutstderr Umleitung und Lesen sie synchron, kann der Ausgangspuffer voll werden und blockieren den Kind-Prozess bei der nächsten schreiben. Dann tritt ein Deadlock auf, weil der übergeordnete Prozess auf das Kind wartet, um zu beenden, bevor er Daten aus dem Puffer liest, das Kind blockiert auf dem Schreiben, weil der Puffer voll ist, also der Deadlock. Die Antwort ist einfach 8211 sein Bestes, um die asynchrone Methode des Lesens von Daten von stdoutstderr zu verwenden. Dieses Problem ist absehbar und war mein schlechtes. Es liegt nicht an mir, es liegt an dir. Ich laufe in eine andere Ausgabe, die wie die gleiche Deadlock aussah, eine, wo eine schlechte Annahme in Microsofts Prozessklasse Umsetzung verursacht eine andere Art von Deadlock zwischen den Eltern-und Kind-Prozesse. Ich fand es, wenn mein Kind-Prozess mich dazu veranlasste, die angeforderte Aktivität zu bestätigen, siehe Abbildung 1 für ein Beispiel. Die Eingabeaufforderung endete ohne eine Zeilenumbrüche, so dass der Cursor am Ende der Eingabeaufforderung (was macht Sinn, warum sollte der Cursor unter der Aufforderung und nicht daneben auf dem Bildschirm). Siehe Abbildung 2 zum Beispiel Code dieser Eingabeaufforderung. Mein Parent-Prozess wurde codiert, um die stdout-Daten zu überprüfen, die asynchron empfangen wurden, und suchten nach der Eingabeaufforderung. Wenn die Aufforderung eingegangen ist, würde der Elternprozess eine Antwort auf die Kinderprozesse stdin ausgeben. Siehe Abbildung 3. Jedoch, wenn ich meinen übergeordneten Prozess ausführe und der untergeordnete Prozess die Eingabeaufforderung gesendet habe, kam der Text niemals in das OutputDataReceived-Ereignis und mein Elternprozess saß auf der p. WaitForExit () - Zeile für immer Der Child-Prozess wartete auf eine Antwort, die Kam nie von den Eltern, und wir waren wieder einmal in einem Deadlock, diesmal war ich es nicht ich. Das Problem war nicht in meinem Code. No NewLine, kein DataReceivedEvent Ich habe angefangen zu debuggen und die OutputDataReceived-Ereignisse zu beobachten und begann den Kind-Prozess-Code auf verschiedene Weise zu ändern. Die untere kleine Änderung verursachte das OutputDataReceived-Ereignis, um mit dem Aufforderungstext zu schießen, siehe Abbildung 4. Aus einigen anderen Tests sieht es aus wie das OutputDataReceived-Ereignis nur dann ausgelöst wird, wenn ein NewLine in der Ausgabe aus dem untergeordneten Prozess ist. Eine Aufforderung ohne eine NewLine würde nicht das OutputDataReceived-Ereignis auslösen und damit der übergeordnete Prozess nicht die Aufforderung bekommen und kann nicht antworten. Deadlock Implementierung meiner eigenen asynchronen Lesung von stdoutstderr Ich muss die Eingabeaufforderungen von einem Kind-Prozess, dass isn8217t mein Code, sondern eine 3rd-Party-Konsole-Anwendung zu lesen, so dass letztlich musste ich in der Lage sein, um Aufforderungen an NewLines zu erhalten. Die Lösung des Problems erforderte mich, meine eigene Async IO Klasse zu implementieren, um den Prozess stdoutstderror zu lesen. Ich habe eine Klasse namens StdStreamReader erstellt, die einen Stream liest und Ereignisse verlässt, die grundsätzlich ähnlich dem Process OutputDataReceived-Ereignis sind. Allerdings ist es nicht möglich, eine NewLine auszuschalten, um ein empfangenes Datenereignis zu löschen, aber stattdessen, sobald Daten empfangen werden. In Abbildung 5 habe ich die Codeunterschiede im Parent-Prozesscode mit der neuen Leserklasse hervorgehoben. Der Code für StdStreamReader ist ziemlich banal, aber das Ergebnis war wie erwartet, siehe Abbildung 6. Beachten Sie, dass Ja nicht kurz nach der Eingabeaufforderung angezeigt wurde, weil es direkt an den untergeordneten Prozess stdin gesendet wurde und nicht angezeigt wurde. Klicken Sie auf Full Source Code. Die auf der Grundlage der Grundkenntnisse ohne jegliche Gewährleistung zur Verfügung gestellt wird.

No comments:

Post a Comment