4

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

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

継承するDispose場合、ファイナライザーは常に呼び出す必要がありますよね?objectIDisposable

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

~BackgroundWorker()
{
    this.Dispose();
}
4

6 に答える 6

11

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

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

ファイナライザーを持つ唯一の理由は、サブクラスが管理されていないリソースを拡張および解放できるようにすることです。サブクラスがない場合は、クラスを封印し、ファイナライザーを完全に削除します。

于 2008-09-29T23:40:09.213 に答える
4

興味深いことに、これがキャンセルを完全にサポートしている通常のBackgroundWorkerを使用できなかった理由は何ですか?

ロックについて - volatile bool フィールドの方が問題が少ないかもしれません。

ただし、この場合、特に「if(disposing)」が指定されている場合、ファイナライザーは興味深いことを何も行っていません。つまり、Dispose() 中に興味深いコードを実行するだけです。個人的には、IDisposable だけに固執し、ファイナライザーを提供しないように誘惑されます。Dispose() でクリーンアップする必要があります。

于 2008-09-30T07:03:39.977 に答える
3

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

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

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

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

  1. Dispose() が呼び出されたかどうか、またはファイナライザーが実行されているかどうかを検出します (ファイナライザー内で、ファイナライズされるオブジェクト以外のマネージド リソースに触れることはできません)。
  2. サブクラスが Dispose() メソッドをオーバーライドできるようにします。
于 2008-09-30T07:30:46.667 に答える
0

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

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

于 2008-09-29T22:35:44.547 に答える
0

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

于 2010-12-02T07:35:03.323 に答える
0

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

于 2008-09-29T23:10:15.183 に答える