Ich habe eine Klasse, die eine Aufgabe startet und sicherstellen möchte, dass die Aufgabe beendet wird, wenn das Objekt als Garbage Collection erfasst wird.Abbrechen einer Aufgabe, wenn ein Objekt abgeschlossen ist
Ich habe das IDisposable-Muster implementiert, um sicherzustellen, dass, wenn das Objekt manuell entsorgt wird oder innerhalb eines Benutzungsblocks verwendet wird, die Aufgabe ordnungsgemäß beendet wird. Allerdings, ich kann nicht garantieren, dass der Endbenutzer Dispose() aufrufen oder das Objekt innerhalb eines Verwendungsblocks verwenden wird. Ich weiß, dass der Garbage Collector letztendlich den Finalizer aufrufen wird - bedeutet das, dass die Aufgabe ausgeführt wird?
public class MyClass : IDisposable
{
private readonly CancellationTokenSource feedCancellationTokenSource =
new CancellationTokenSource();
private readonly Task feedTask;
public MyClass()
{
feedTask = Task.Factory.StartNew(() =>
{
while (!feedCancellationTokenSource.IsCancellationRequested)
{
// do finite work
}
});
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
feedCancellationTokenSource.Cancel();
feedTask.Wait();
feedCancellationTokenSource.Dispose();
feedTask.Dispose();
}
}
~MyClass()
{
Dispose(false);
}
}
Es wurde in this question empfohlen, einen flüchtigen Bool hinzuzufügen, die von den Finalizer und beobachtet von der Aufgabe festgelegt ist. Wird das empfohlen, oder gibt es einen besseren Weg, um das zu erreichen, was ich brauche?
(Ich verwende .NET 4 daher die Verwendung von TaskFactory.StartNew statt Task.Run)
EDIT:
Um einige Kontext auf die Frage zu geben - was nicht wirklich gezeigt wird Im obigen Code-Snippet: Ich erstelle eine Netzwerk-Client-Klasse, die einen Mechanismus zum Leben erhält, indem regelmäßig Pakete an den Server gesendet werden. Ich habe mich entschieden, dieses Detail nicht in das Beispiel aufzunehmen, da es für meine spezifische Frage nicht relevant war. Was ich jedoch tatsächlich möchte, ist die Möglichkeit für den Benutzer, eine boolesche KeepAlive-Eigenschaft auf "true" zu setzen, wodurch eine Aufgabe gestartet wird, um alle 60 Sekunden Daten an den Server zu senden. Wenn der Benutzer die Eigenschaft auf false setzt, wird die Aufgabe beendet. IDisposable hat mich zu 90% dorthin gebracht, aber es hängt davon ab, dass der Benutzer es ordnungsgemäß entsorgt (explizit oder über die Nutzung). Ich möchte keine Keep-Alive-Aufgaben für den Benutzer offenlegen, damit sie explizit abbrechen. Ich möchte nur ein "einfaches" KeepAlive = true/false, um die Aufgabe zu starten/stoppen UND ich möchte, dass die Aufgabe beendet wird, wenn der Benutzer fertig ist das Objekt - auch wenn sie es nicht ordnungsgemäß entsorgen. Ich fange an zu denken, dass dies nicht möglich ist!
Warum nicht 'System.Timers.Timer' verwenden? –
Dieser Code wird im Finalizer nichts bewirken. Das ist ein Fehler. Da die Aufgabe über den Schließungszustand der äußeren MyClass-Instanz gehalten wird, wird dieses Objekt niemals finalisiert, bis die Aufgabe auf natürliche Weise beendet wird. – usr
@Danny Chen Ich dachte das - aber hat das das gleiche Problem? Wie ich es verstehe, würde der Timer weiter laufen, selbst wenn das Objekt, das es erstellt hat, entsorgt wird (bitte korrigieren Sie mich, wenn ich falsch liege)! Ich überlegte, AutoReset auf "false" zu setzen und die Callback-Methode manuell jedesmal neu zu setzen, wenn es "tickt" - aber dann war ich nicht sicher, ob der GC das Objekt jemals fertigstellen würde, wenn er ein Ereignis abonniert hat. Irgendwelche Vorschläge würden geschätzt! –