Frage

Ich habe eine Klasse mit dem Namen BackgroundWorker bekam, die einen Faden ständig hat. Um diesen Thread zu deaktivieren, eine Instanzvariable namens stop bedarfsgerecht zu true.

Um sicherzustellen, dass der Thread freigegeben wird, wenn die Klasse getan wird verwendet, ich habe hinzugefügt IDisposable und einen Finalizer, die Dispose() aufruft. Unter der Annahme, dass in der Tat stop = true dieser Thread verursacht zu verlassen, ist dies sippet richtig? Es ist in Ordnung Dispose von einem Finalizer aufrufen, nicht wahr?

Finalizer sollten immer nennen Dispose wenn die object IDisposable erbt, nicht wahr?

/// <summary>
/// Force the background thread to exit.
/// </summary>
public void Dispose()
{
    lock (this.locker)
    {
        this.stop = true;
    }
}

~BackgroundWorker()
{
    this.Dispose();
}
War es hilfreich?

Lösung

Der Code ist in Ordnung, wenn auch in einem Finalizerthread Verriegelungs etwas „unheimlich“ ist und ich würde es vermeiden - wenn Sie einen Deadlock ... Ich bin nicht 100% sicher, was passieren würde, aber es wäre nicht gut. wenn Sie sicher sind, soll dies jedoch nicht ein Problem sein. Meist. Die Interna von Garbage Collection sind schmerzhaft, und ich hoffe, dass Sie nie, sie zu sehen haben;)

Wie Marc GRA weist darauf hin, ein flüchtiges Bool Sie erlauben würde, loszuwerden, die Sperre zu bekommen, die dieses Problem mildern würde. Implementieren Sie diese Änderung, wenn Sie können.

nedruod Code legt die Zuordnung innerhalb des if (disposing) zu überprüfen, was völlig falsch ist - der Thread eine nicht verwaltete Ressource ist und sogar gestoppt werden muß, wenn nicht explizit zu entsorgen. Der Code ist in Ordnung, ich bin nur darauf hin, dass Sie den Rat in diesem Code-Schnipsel gegeben nicht nehmen sollen.

Ja, Sie fast immer sollten Dispose () von der Finalizerthread nennen, wenn das IDisposable-Muster zu implementieren. Das vollständige IDisposable Muster ist ein bisschen größer als das, was Sie haben, aber Sie müssen nicht immer - es gibt nur zwei zusätzliche Möglichkeiten:

  1. Erkennen, ob Dispose () aufgerufen wurde oder der Finalizer ausgeführt wird (Sie keine verwalteten Ressourcen im Finalizerthread zu berühren erlaubt, außerhalb des Objekts abgeschlossen ist);
  2. Aktivieren Subklassen die Dispose () -Methode außer Kraft zu setzen.

Andere Tipps

Zunächst einmal, eine ernste Warnung . Verwenden Sie keine Finalizer verwenden wie Sie sind. Sie setzen sich für einige sehr schlechte Auswirkungen, wenn Sie Schlösser in einem Finalizerthread nehmen. Kurzgeschichte ist es nicht tun. Nun auf die ursprüngliche Frage.

public void Dispose()
{
    Dispose(true);
    GC.SuppressFinalize(this);
}

/// <summary>
/// Force the background thread to exit.
/// </summary>
protected virtual void Dispose(bool disposing)
{
    if (disposing)
    {
        lock (this.locker)
        {
            this.stop = true;
        }
    }
}

~BackgroundWorker()
{
    Dispose(false);
}

Der einzige Grund, einen Finalizer überhaupt haben Unterklassen zu ermöglichen, zu erweitern und lösen nicht verwalteten Ressourcen . Wenn Sie keine Unterklassen haben dann Ihre Klasse versiegeln und die Finalizerthread vollständig fallen.

Sie müssen das volle Einweg-Muster, aber der Anschlag etwas sein, hat der Thread zugreifen kann. Wenn es sich um eine Membervariable der Klasse ist, angeordnet ist, das ist nicht gut, weil es keinen angeordnet Klasse verweisen können. Betrachten wir ein Ereignis mit, dass das Gewinde besitzt und signalisiert, dass auf dispose statt.

Das Objekt, das die finalizer einen Verweis auf ein Flag benötigt implementiert - gespeichert in einem anderen Objekt - die der Faden wird sehen können; der Faden muß nicht hat keine starke Referenz, die direkt oder indirekt auf das Objekt, das die Finalizerthread implementiert. Der Destruktor sollte die Fahne mit so etwas wie ein CompareExchange gesetzt, und der Faden soll ein ähnliches Mittel verwenden, es zu testen. Beachten Sie, dass, wenn der Finalizer eines Objekts auf ein anderes Objekt zugreift, kann das andere Objekt finalisiert wurden, aber es wird noch existieren. Es ist in Ordnung für ein Finalizerthread andere Objekte zu verweisen, wenn sie dies in einer Weise tut, die nicht von ihren Abschluss gestört wird. Wenn alles, was Sie tun, ist ein Flag gesetzt, du bist in Ordnung.

scroll top