So entsorgen Sie asynchron?
Sagen wir ich habe eine Klasse, die die IDisposable - Schnittstelle. So etwas wie dieses:
MyClass verwendet einige nicht verwaltete Ressourcen, damit die Dispose() Methode von IDisposable Versionen dieser Ressourcen. MyClass sollte auch so eingesetzt werden:
using ( MyClass myClass = new MyClass() ) {
myClass.DoSomething();
}
Nun, ich möchte, um eine Methode zu implementieren, die Anrufe DoSomething() asynchron. Ich füge eine neue Methode zur MyClass:
Nun von der client-Seite, MyClass sollte auch so eingesetzt werden:
using ( MyClass myClass = new MyClass() ) {
myClass.AsyncDoSomething();
}
Jedoch, wenn ich nicht etwas anderes tun, könnte dies fehlschlagen, da das Objekt myClass könnte entsorgt werden, bevor DoSomething() genannt wird (und werfen ein unerwartetes ObjectDisposedException). Also, der Aufruf an die Dispose() Methode (entweder implizit oder explizit) sollte solange verzögert, bis der asynchrone Aufruf DoSomething() ist getan.
Ich denke, der code in der Dispose() Methode ausgeführt werden soll in einer asynchronen Art und Weise, und nur einmal alle asynchronen Aufrufe werden aufgelöst,. Ich würde gerne wissen, was könnte der beste Weg, dies zu erreichen.
Dank.
HINWEIS: der Einfachheit halber, habe ich noch nicht eingegeben in die details, wie die Dispose () - Methode implementiert ist. Im realen Leben habe ich in der Regel Folgen die Dispose-Muster.
UPDATE: ich Danke Ihnen so sehr für Ihre Antworten. Ich schätzen Ihre Bemühungen. Als chakrit hat kommentiert, brauche ich mehrere Aufrufe der async DoSomething gemacht werden können. Im Idealfall sollte sowas funktionieren:
using ( MyClass myClass = new MyClass() ) {
myClass.AsyncDoSomething();
myClass.AsyncDoSomething();
}
Ich studieren werde, die counting semaphore, es scheint, was ich Suche. Es könnte auch ein design-problem. Wenn ich es bequem finden, ich werde mit Ihnen teilen einige bits von dem realen Fall und was MyClass wirklich tut.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Wie es aussieht bist du mit dem event-based async-pattern (siehe hier für mehr Informationen .NET async-Muster) also, was würden Sie haben in der Regel eine Veranstaltung, in der Klasse, der ausgelöst wird, wenn der asynchrone Vorgang abgeschlossen ist benannt
DoSomethingCompleted
(beachten Sie, dassAsyncDoSomething
sollte wirklich genannt werdenDoSomethingAsync
Folgen dem Muster nicht richtig). Mit diesem Ereignis ausgesetzt, könnten Sie schreiben:Die andere alternative ist die Verwendung der
IAsyncResult
Muster, wo Sie einen Delegaten übergeben kann, ruft die dispose-Methode, um dieAsyncCallback
parameter (mehr info-auf dieses Muster ist in der oben genannten Seite auch). In diesem Fall würden Sie habenBeginDoSomething
undEndDoSomething
Methoden stattDoSomethingAsync
, und würde Anruf es so etwas wie...Aber, egal welchen Weg Sie es tun, müssen Sie eine Möglichkeit für den Anrufer mitgeteilt werden, dass der asynchrone Vorgang abgeschlossen ist, so kann es entsorgen Sie das Objekt an die richtige Zeit.
Dispose
heißt, jemand anderes kann mit einem Objekt, das dieDispose
Methode beeinträchtigen würde.Async-Methoden haben in der Regel einen Rückruf sodass Sie einige Schritte nach Fertigstellung. Wenn dies Ihr Fall, es wäre so etwas wie dieses:
Einen anderen Weg, um dieses ist eine asynchrone wrapper:
Ich würde nicht den code ändern, irgendwie zu ermöglichen async verfügt. Stattdessen würde ich sicherstellen, dass, wenn der Anruf zu AsyncDoSomething gemacht wird, wird es eine Kopie von allen Daten, die er ausführen muß. Diese Methode sollte verantwortlich sein für die Reinigung bis alle wenn seiner Ressourcen.
Fügen Sie eine callback-Mechanismus, und eine cleanup-Funktion als callback.
aber dieses problem darstellen würde, wenn Sie mehrere asynchrone Aufrufe von der gleichen Objekt-Instanz.
Eine Möglichkeit wäre, eine einfache Implementierung counting semaphore mit der Semaphore-Klasse zum zählen der Anzahl der ausgeführten async-jobs.
Fügen Sie die Zähler, MyClass und auf jeden AsyncWhatever fordert, erhöht sich der Zähler, auf den Ausgängen decerement es. Wenn die semaphore 0 ist, dann ist die Klasse bereit ist, entsorgt werden.
Aber ich bezweifle, dass wäre der ideale Weg. Ich rieche ein design-problem. Vielleicht ein re-Gedanken von MyClass designs könnten dies vermeiden?
Könnten Sie teilen sich einige etwas von MyClass Umsetzung? Was es tun soll?
Halte ich es schade, dass Microsoft nicht verlangen, als Teil der
IDisposable
Vertrag, Implementierungen ermöglichen sollteDispose
genannt zu werden, von jedem threading-Kontext, da es keine vernünftige Möglichkeit der Erzeugung eines Objekts können erzwingen, dass der Fortbestand des threading-Kontext, in dem es erstellt wurde. Es ist möglich, design code, so dass der thread, der ein Objekt erstellt wird, irgendwie sehen die für das Objekt obsolet und kannDispose
auf seine Bequemlichkeit, und so, dass, wenn der thread nicht mehr benötigt, für alles andere wird es bleiben, bis alle entsprechenden Objekte wurdenDispose
d, aber ich glaube nicht, dass es einen standard-Mechanismus, erfordert keine spezielle Verhalten auf dem Teil von dem thread erstellen dieDispose
.Ihre beste Wette ist wahrscheinlich, um alle Objekte von Interesse in einem gemeinsamen thread (vielleicht der UI-thread), versuchen zu garantieren, dass der thread bleiben, um für die Lebensdauer der Objekte von Interesse, und so etwas wie
Control.BeginInvoke
auf Wunsch die Objekte zur Verfügung stehen. Vorausgesetzt, dass weder der Objekterstellung noch der cleanup-block wird für jede Länge der Zeit, das ist ein guter Ansatz, aber wenn entweder der Vorgang konnte block einen anderen Ansatz erforderlich sein kann [vielleicht zu öffnen, einen versteckten dummy-Formular mit seinen eigenen thread, so kann manControl.BeginInvoke
es].Alternativ, wenn Sie die Kontrolle über die
IDisposable
- Implementierungen zu gestalten, so dass Sie können sicher geschossen werden asynchron. In vielen Fällen, das wird "einfach so" funktionieren, vorausgesetzt niemand versucht, den Gegenstand, wenn es entsorgt wird, aber das ist kaum ein gegeben. Insbesondere, mit vielen Arten vonIDisposable
, es gibt eine Reale Gefahr, dass mehrere Objekt-Instanzen können sowohl zu manipulieren, eine gemeinsame außen-Ressource (z.B. ein Objekt halten darf, einList<>
des erstellten Instanzen, hinzufügen von Instanzen in die Liste ein, wenn Sie aufgebaut sind, und entfernen Sie Instanzen aufDispose
; wenn die Liste Operationen nicht synchronisiert sind, wird ein asynchronerDispose
korrumpieren könnte die Liste auch wenn das Objekt entsorgt nicht anderweitig in Gebrauch ist.BTW, ein nützliches pattern ist für Objekte zu ermöglichen asynchrone entsorgen, während Sie verwendet werden, mit der Erwartung, dass eine solche Verfügung wird dazu führen, alle Operationen im Gange, um eine exception zu werfen auf die erste günstige Gelegenheit. Dinge wie sockets funktionieren auf diese Weise. Es kann nicht möglich sein, für eine read-operation vorzeitig beenden, ohne den sockel in einen nutzlosen Zustand, aber wenn die Buchse nie verwendet, trotzdem gibt ' s keinen Punkt für das Lesen zu halten, warten auf Daten, wenn ein anderer thread hat festgestellt, dass er aufgeben sollte. IMHO, das ist, wie alle
IDisposable
Objekte sollten sich bemühen, sich zu Verhalten, aber ich kenne kein Dokument verlangt eine Allgemeine Muster.Also, meine Idee ist, zu halten, wie viele AsyncDoSomething() anhängig ist, abgeschlossen ist, und nur dann entsorgen, wenn diese Anzahl erreicht ist, auf null. Mein Erster Ansatz ist:
Einige Probleme können auftreten, wenn zwei oder mehr threads versuchen zu Lesen /schreiben pendingTasks Variablen gleichzeitig, so die lock keyword sollte verwendet werden, um zu verhindern, dass race conditions:
Sehe ich ein problem mit diesem Ansatz. Da die Freisetzung von Ressourcen wird asynchron durchgeführt, so etwas wie dies funktionieren könnte:
Wenn das erwartete Verhalten sein sollte, starten Sie eine ObjectDisposedException wenn DoSomething() heißt außerhalb der mit - Klausel. Aber ich glaube nicht, dass dies schlecht genug, um überdenken dieser Lösung.