2012-05-24 14 views
10

Nachdem meine Anwendung einfror, habe ich die Ursache zu einem Thread auf eine Aufgabe von Task.Delay() (oder TaskEx.Delay() in .NET 4.0), für die es eine berechnete TimeSpan, die aufgrund eines Fehlers, wurde gelegentlich zu einer TimeSpan berechnet wurde warten auf einen Thread mit einer TotalMilliseconds von kleiner oder gleich -1 und größer als -2 (dh irgendwo zwischen -10000 bis -19999 Ticks, inklusive).Warum erlaubt Task.Delay() eine unendliche Verzögerung?

Es scheint, dass, wenn Sie eine negative TimeSpan übergeben, die -2 Millisekunden oder weniger beträgt, wobei das Verfahren korrekt ein ArgumentOutOfRangeException wirft, aber wenn man einen negativen Zeitraum von dem oben beschriebenen Bereich bereitzustellen, gibt es eine Task, die nie Einstellung (von abgeschlossen der zugrundeliegende System.Threading.Timer zu einem dueTime von -1, der unendlich bezeichnet). Das bedeutet, dass alle Fortsetzungen, die für diese Aufgabe festgelegt wurden, niemals ausgeführt werden und ein fehlerhafter Thread, der mit .Wait() auf dieser Task passiert, wird für immer blockiert.

Welche mögliche Verwendung kann eine Task, die nie abgeschlossen haben? Würde jemand solch einen Rückgabewert erwarten? Sollte kein negativer Wert an .Delay() übergeben werden, einschließlich Werte in diesem speziellen Bereich, einen ArgumentOutOfRangeException werfen?

+1

Das MSDN-Dokument ist ziemlich explizit in -1, so scheint es korrekt zu sein. Ich bin mir nicht sicher über den Anwendungsfall für diese Überladung, aber es könnte eine Art sein, auf eine "nur" Löschung mit der Überlast zu warten, die ein Löschungs-Token benötigt. –

+0

@James: Es ist nicht explizit erlaubt -1, es ist explizit zu verbieten Werte unter -1. Es wird nicht einmal gesagt, was passieren wird, wenn Sie -1 übergeben, anders als in der Dokumentation von 'System.Threading.Timer'. Es scheint fast so, als ob die dokumentierte Liste der Ausnahmen automatisch aus dem Quellcode generiert würde. Und wenn Sie auf "nur" eine Absage warten, warum rufen Sie sogar "Task.Delay()" an? –

+0

Wenn Sie denken, dass es kaputt ist, melden Sie einen Fehler beim Verbinden. Ein Dokument, das sagt "niedriger als -1 ist ungültig", ist explizit (für mich), dass -1 gültig ist. Wenn die Absicht -1 als ungültig wäre, wäre "niedriger als 0 ungültig" einfacher zu schreiben. Da das doc und der Code beide -1 erlauben, denke ich, dass dies By Design ist, aber fühlen Sie sich frei, einen Fehler beim Verbinden zu machen (eher vom BCL-Team verarbeitet als ein zufälliger SO-Thread, würde ich denken :) –

Antwort

7

Timeout.Infinite oder -1 ist nützlich, wenn Sie unbegrenzt auf eine lang andauernde Aufgabe warten möchten, die eine unbestimmte Zeit in Anspruch nimmt, aber schließlich abgeschlossen wird.

Die Win32-API verwendet auch eine Konstante INFINITE = -1 für unbegrenzte Timeouts.

Normalerweise würden Sie es nicht in einem UI-Thread verwenden, da es die Benutzeroberfläche einfrieren könnte (was Ihr Problem zu sein scheint). Aber es gibt gültige Anwendungsfälle in einem Worker-Thread - z. Ein Server, der das Warten auf eine Verbindung von einem Client blockiert.

+0

Eine unendliche Zeitüberschreitung ist nützlich. Eine unendliche Verzögerung ist nicht (und daher gilt der erste Absatz nicht). Was in der Welt würdest du für immer verzögern wollen? Sie können es auch einfach nicht ausführen. Es macht einfach keinen Sinn für mich, dass das Implementierungsdetail von "-1" von "System.Threading.Timer" (oder dem Win32-Timer) bis zur "Task.Delay()" -Methode propagiert wird.Es widerspricht Microsofts Design-Prinzip, Entwickler in die "Grube des Erfolgs" zu drängen, es sei denn, es gibt einige Anwendungsfälle, die mir nicht bekannt sind. –

+0

Außerdem verwende ich es nicht in einem UIhread. Es ist ein Windows-Dienst, der beim Beenden eine Shutdown-Routine ausführen muss, indem er eine auf [TAP] (http://www.microsoft.com/de-de/download/details.aspx?id=19957) basierende Methode aufruft Das kann zu lange dauern, um es auszuführen, und es wird auch eine Verzögerungsaufgabe erstellt, die eine erzwungene Abschaltung durchführt. Dann führt er eine '.WaitAny()' auf beiden Tasks aus, und da die ursprüngliche Task extrem lange gedauert hat und die Verzögerungsaufgabe niemals abgeschlossen wird (anstatt eine Ausnahme auszulösen), schien der Dienst zu hängen. –

+1

Wie würde ein Server, der das Warten auf eine Verbindung von einem Client blockiert, eine "Task" verwenden, die niemals abgeschlossen wird? Könnten Sie ein Beispiel zeigen? –

2

In Mocking-Szenarien, in denen ich sicherstellen möchte, dass mein Code in einem Task.WhenAny() - Block eine der Aufgaben korrekt verarbeitet, kann ich die anderen Aufgaben verspotten und eine unendliche Verzögerung verwenden, um sicherzustellen, dass die Aufgabe .Wenn jemand die Aufgabe bearbeitet, verspottete ich nicht als unendliche Verzögerung.

+2

Interessanter Anwendungsfall, obwohl ich denke, es wäre expliziter und klarer, 'neue TaskCompletionSource() .Task' zu verwenden, um eine nie endende Aufgabe zu liefern. –

Verwandte Themen