質問

スレッドが常に実行されている BackgroundWorker という名前のクラスがあります。このスレッドをオフにするには、 stop という名前のインスタンス変数を true にする必要があります。

クラスの使用が終了したときにスレッドが確実に解放されるように、 IDisposable と、 Dispose()を呼び出すファイナライザーを追加しました。 stop = true が実際にこのスレッドを終了させると仮定すると、この断片は正しいですか?ファイナライザから Dispose を呼び出しても構いませんか?

オブジェクトが IDisposable を継承する場合、

ファイナライザーは常に Dispose を呼び出す必要がありますか?

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

~BackgroundWorker()
{
    this.Dispose();
}
役に立ちましたか?

解決

ファイナライザのロックは多少「怖い」ですが、コードは問題ありません。そして、私はそれを避けるだろう-あなたがデッドロックを取得した場合...私は何が起こるかを100%確信していないが、それは良くないだろう。ただし、安全であれば、これは問題になりません。主に。ガベージコレクションの内部は苦痛であり、それらを見る必要がないことを願っています;)

Marc Gravellが指摘しているように、揮発性boolを使用するとロックを解除でき、この問題を軽減できます。可能であれば、この変更を実装します。

nedruodのコードは、if(破棄)チェック内に割り当てを配置しますが、これは完全に間違っています-スレッドはアンマネージリソースであり、明示的に破棄しなくても停止する必要があります。あなたのコードは問題ありません。そのコードスニペットで与えられたアドバイスを受け入れてはいけないことを指摘しているだけです。

はい、IDisposableパターンを実装する場合、ファイナライザーからDispose()を呼び出す必要がほとんどです。完全なIDisposableパターンは、あなたが持っているものよりも少し大きいですが、必ずしもそれを必要とするわけではありません-それは単に2つの追加の可能性を提供するだけです:

  1. Dispose()が呼び出されたか、ファイナライザが実行されているかを検出します(ファイナライズされているオブジェクトの外部では、ファイナライザの管理対象リソースに触れることはできません)
  2. サブクラスを有効にしてDispose()メソッドをオーバーライドします。

他のヒント

まず、重大な警告。あなたのようにファイナライザを使用しないでください。ファイナライザ内でロックを取得すると、いくつかの非常に悪い影響が発生します。短い話はそれをしないでください。元の質問に戻ります。

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);
}

ファイナライザーを使用する唯一の理由は、サブクラスがアンマネージリソースを拡張および解放できるようにすることです。サブクラスがない場合は、クラスを封印し、ファイナライザを完全にドロップします。

興味深いことに、これが通常の BackgroundWorker 、キャンセルを完全にサポートしていますか

ロックを再設定します-揮発性のブールフィールドはそれほど面倒ではありません。

ただし、この場合、特に&quot; if(disposing)&quot;が与えられた場合、ファイナライザは何も面白いことをしていません。 -つまり、Dispose()中に興味深いコードのみを実行します。個人的には、IDisposableだけを使い、ファイナライザーは提供しないようにしたいと思います。Dispose()でクリーンアップする必要があります。

は「停止」ですインスタンス変数のプロパティ?そうでない場合、ファイナライザ中に設定することに特別なポイントはありません。オブジェクトを参照しているものはないため、メンバーを照会することはできません。

実際にリソースを解放する場合は、Dispose()とファイナライザに同じ作業を実行させる(作業を行う必要があるかどうかを最初にテストする)のが良いパターンです。

完全な使い捨てパターンが必要ですが、ストップはスレッドがアクセスできるものでなければなりません。破棄されるクラスのメンバー変数である場合、破棄されたクラスを参照できないため、それは良くありません。スレッドが所有するイベントを用意し、代わりに破棄時に通知することを検討してください。

ファイナライザを実装するオブジェクトには、スレッドへの参照が可能なフラグへの参照が必要です(フラグは別のオブジェクトに保存)。スレッドは、ファイナライザを実装するオブジェクトへの直接または間接の強い参照を してはなりません。ファイナライザは、CompareExchangeなどを使用してフラグを設定し、スレッドは同様の手段を使用してテストする必要があります。あるオブジェクトのファイナライザが別のオブジェクトにアクセスする場合、他のオブジェクトはファイナライズされている可能性がありますが、まだ存在することに注意してください。ファイナライザーが他のオブジェクトを参照するのは、ファイナライズによって煩わされない方法で参照する場合は問題ありません。フラグを設定するだけであれば、問題ありません。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top