Ich suche nach guten Ideen für die Implementierung einer generischen Methode, um eine einzelne Zeile (oder einen anonymen Delegaten) von Code mit einer Zeitüberschreitung auszuführen.
TemperamentalClass tc = new TemperamentalClass();
tc.DoSomething(); // normally runs in 30 sec. Want to error at 1 min
Ich suche nach einer Lösung, die an vielen Stellen elegant implementiert werden kann, an denen mein Code mit temperamentvollem Code interagiert (den ich nicht ändern kann).
Außerdem möchte ich, dass der fehlerhafte "Timeout" -Code nach Möglichkeit nicht mehr weiter ausgeführt wird.
c#
multithreading
c#-3.0
asynchronous
timeout
chilltemp
quelle
quelle
Antworten:
Der wirklich schwierige Teil hier war, die lange laufende Aufgabe zu beenden, indem der Executor-Thread von der Aktion an einen Ort zurückgeleitet wurde, an dem er abgebrochen werden konnte. Ich habe dies mit der Verwendung eines umschlossenen Delegaten erreicht, der den Thread zum Töten in eine lokale Variable in der Methode übergibt, mit der das Lambda erstellt wurde.
Ich reiche dieses Beispiel zu Ihrem Vergnügen ein. Die Methode, an der Sie wirklich interessiert sind, ist CallWithTimeout. Dadurch wird der lange laufende Thread abgebrochen, indem er abgebrochen und die ThreadAbortException verschluckt wird :
Verwendung:
Die statische Methode, die die Arbeit erledigt:
quelle
Wir verwenden Code wie diesen häufig in der Produktion :
Die Implementierung erfolgt über Open Source, funktioniert auch in parallelen Computerszenarien effizient und ist als Teil von Lokad Shared Libraries verfügbar
Dieser Code ist immer noch fehlerhaft. Sie können ihn mit diesem kleinen Testprogramm ausprobieren:
Es gibt eine Rennbedingung. Es ist eindeutig möglich, dass eine ThreadAbortException ausgelöst wird, nachdem die Methode
WaitFor<int>.Run()
aufgerufen wurde. Ich habe keinen zuverlässigen Weg gefunden, um dies zu beheben, aber mit demselben Test kann ich kein Problem mit der von TheSoftwareJedi akzeptierten Antwort wiederholen .quelle
Nun, Sie könnten Dinge mit Delegaten tun (BeginInvoke, mit einem Rückruf, der ein Flag setzt - und dem ursprünglichen Code, der auf dieses Flag oder Timeout wartet) -, aber das Problem ist, dass es sehr schwierig ist, den laufenden Code herunterzufahren. Zum Beispiel ist das Töten (oder Anhalten) eines Threads gefährlich ... daher glaube ich nicht, dass es einen einfachen Weg gibt, dies robust zu tun.
Ich werde dies posten, aber beachten Sie, dass es nicht ideal ist - es stoppt die lang laufende Aufgabe nicht und bereinigt bei einem Fehler nicht richtig.
quelle
Einige kleinere Änderungen an Pop Catalins großartiger Antwort:
Überladungen wurden hinzugefügt, um den Signalisierungs-Worker beim Abbrechen der Ausführung zu unterstützen:
quelle
So würde ich es machen:
quelle
Ich habe das gerade ausgeknockt, damit es vielleicht etwas verbessert werden muss, aber ich werde tun, was Sie wollen. Es ist eine einfache Konsolen-App, zeigt jedoch die erforderlichen Prinzipien.
quelle
Was ist mit Thread.Join (int timeout)?
quelle