2010-08-11 4 views
22

ich zur Zeit etwas mit nach Hause gebacken Aufgabe Funktionalität mit einer neuen Implementierung mit der neuen System.Threading.Tasks Funktionalität in .net gefunden ersetzen 4.Wie Benachrichtigung erhalten, die eine System.Threading.Tasks.Task abgeschlossen hat

Ich habe allerdings ein kleines Problem, und obwohl ich mir einige Lösungen vorstellen kann, hätte ich gerne einen Ratschlag, welcher der beste Weg ist, um es zu tun, und ob ich irgendwo einen Trick verpasse.

Was ich brauche, ist für einen willkürlichen Prozess in der Lage zu sein, eine Aufgabe zu starten, aber dann weitermachen und nicht auf den Abschluss der Aufgabe warten. Kein Problem, aber wenn ich dann etwas mit dem Ergebnis einer Aufgabe machen muss, bin ich mir nicht sicher, wie es am besten geht.

Alle Beispiele, die ich gesehen habe, verwenden entweder Wait() für die Aufgabe, bis sie den Ergebnisparameter für die Aufgabe vervollständigt oder darauf verweist. Beide blockieren den Thread, der die Aufgabe gestartet hat, was ich nicht möchte.

Einige Lösungen dachte ich haben von:

  1. einen neuen Thread erstellen und die Aufgabe auf, dass starten, verwenden Sie dann Wait() oder .RESULT den neuen Thread zu blockieren und das Ergebnis zurück an den Anrufer synchronisieren irgendwie, möglicherweise mit Abfragen zu den Aufgaben IsCompleted Parameter.

  2. Haben Sie eine 'Benachrichtigen abgeschlossen' Aufgabe, die ich nach Abschluss der Aufgabe, die ich ausführen möchte, die dann ein statisches Ereignis oder etwas löst.

  3. Übergeben Sie einen Delegaten in die Eingabe der Aufgabe und rufen Sie diesen auf, um zu benachrichtigen, dass die Aufgabe beendet ist.

ich denken kann, oder Vor-und Nachteile für alle von ihnen, aber ich besonders mag nicht die Idee, explizit einen neuen Thread zu erstellen, die Aufgabe zu beginnen, wenn die eines der Ziele der Verwendung Aufgabenklasse besteht in erster Linie darin, von der direkten Verwendung von Threads zu abstrahieren.

Irgendwelche Gedanken über den besten Weg? Fehle ich etwas Einfaches? Wäre ein "Completed" Event zu viel verlangt? (Sicher gibt es einen guten Grund, warum es nicht ein!)

+0

Aus Neugier, warum nicht BackgroundWorker verwenden? Es hat die Aufgabe abgeschlossen, sowie Stornierung Benachrichtigung. – Robaticus

+1

'BackgroundWorker' wird jetzt nicht mehr benötigt, da' Task' bei uns ist. BGW benötigt einen 'SynchronizationContext', der optional mit' Task' (ermöglicht größere Parallelität) ist. –

Antwort

26

I Verdächtiger Sie suchen Task.ContinueWith (oder Task<T>.ContinueWith). Sie sagen im Wesentlichen: "Wenn Sie diese Aufgabe abgeschlossen haben, führen Sie diese Aktion aus." Es gibt jedoch verschiedene Optionen, die Sie angeben können, um mehr Kontrolle darüber zu haben.

MSDN geht viel in diesem Detail in "How to: Chain Multiple Tasks With Continuations" und "Continuation Tasks".

+0

Ja, ich verstehe das, aber es löst nicht das Problem, zu wissen, wann die Sequenz von Tasks beendet wurde, ohne Task.Wait() (und damit Blockierung) für den Thread aufzurufen, der die Task gestartet hat. Ein Ansatz, an den ich dachte (wie oben), war die Verwendung von Task.ContinueWith, um eine Aufgabe zu verketten, die ein Ereignis auslöst, an dem sich Interessenten beteiligen können. Dies wird die ursprüngliche Aufgabe atomar halten. –

+1

@bwilliams: Warum nicht einfach die Aufgabe aufdecken, und Interessenten können 'Task.ContinueWith' nennen? Ich sehe nicht, auf welche Weise * es * nicht das Problem löst, zu wissen, wann die Aufgabe abgeschlossen ist ... es ist ein nicht blockierender Anruf, der sagt: "Ruf mich zurück, wenn das erledigt ist." –

+1

(Oder, anstatt die Aufgabe selbst zu offenbaren, können Sie Ihre eigene Methode bereitstellen, die intern nur 'ContinueWith' aufruft. Es ist das Gleiche, wirklich.) –

4

Sie können eine task continuation anwenden.

Alternativ implementiert TaskIAsyncResult, so können Sie die standard approaches for that interface (Blockierung, Polling oder wartet auf seine WaitHandle) verwenden.

+0

Für die Aufgabe Fortsetzung Thema finden Sie bitte meinen Kommentar unter Jon Skeets Beitrag. Blockieren und Abfragen Ich mag die Idee nicht, da dies bedeutet, dass ich einen anderen Thread starten muss, um den ursprünglichen Thread zu behalten, der die Aufgabe gestartet hat. Ich habe gesehen, ich könnte WaitHandle verwenden, aber die Dokumentation sagt, die bevorzugte Methode ist, Task.Wait() zu verwenden. Das heißt, da das nicht das macht, was ich will, ist vielleicht das WaitHandle das Beste für mich –

4

In modernen C# muss nicht mehr explizit ContinueWith() aufgerufen werden. Eine Alternative zu der ursprünglichen akzeptierten Antwort wäre, einfach eine async Methode zu erstellen, die await s Task in Frage stellt, und tut, was auch immer es wünscht, wenn die Task abgeschlossen ist.

Angenommen, Sie möchten ein Ereignis namens TaskCompleted auslösen, wenn die Task abgeschlossen ist. Sie würden eine Methode wie schreiben:

async Task RaiseEventWhenTaskCompleted(Task task) 
{ 
    await task; 
    TaskCompleted?.Invoke(this, EventArgs.Empty); 
} 

Um die Wartezeit zu "registrieren", rufen Sie einfach die obige Methode auf. Fügen Sie die Ausnahmebehandlung wie gewünscht hinzu, entweder in der obigen Methode oder in einem Code, der eventuell die Task, die von der obigen Methode zurückgegeben wird, beobachtet.

Verwandte Themen