複数のスレッド間でアクセスできるIDisposable
オブジェクトがあります。私は、オブジェクトがクリーンアップを実行する前に "使用中"であることを追跡する方法を理解しようとしています。つまり、実行中のメソッドが完了すると減少するように、何らかの参照カウントを保持して、Disposeメソッドがすべて完了するまで(またはタイムアウトが経過するまで)続行しないようにする必要があります。 。しかし、Method
への今後の呼び出しが失敗すると、一度Dispose
に入ったことを確認する必要があります。 。のようなIDisposableの同時オブジェクトアクセスのトラッキング
何か:Method()
が再び呼び出されると_stopping
が設定されていないが、Dispose
は、他のすべてを無効にする、継続するため
class MyObject : IDisposable
{
private long _counter;
private bool _stopping;
private IDisposable _someResource;
public void Method()
{
if (_stopping)
throw new InvalidOperationException();
Interlocked.Increment(ref _counter);
try
{
// do some work
}
finally
{
Interlocked.Decrement(ref _counter);
}
}
public void Dispose()
{
var timeout = DateTime.Now.Add(TimeSpan.FromSeconds(15));
while (DateTime.Now < timeout && Volatile.Read(ref _counter) > 0)
{
// wait
// Thread.Sleep(10) or something
}
_stopping = true;
//perform clean up
_someResource.Dispose();
}
}
は、しかし、これは動作しません。
ここで使用できる特定のパターン、またはこれを解決するために使用できるフレームワーククラスがありますか?基本的に双方向信号であるDispose
に何も処理中でないことが伝えられているので、その信号が失敗するはずです。Method
私はCountdownEventを見つけましたが、ここでどのように使用できるかはわかりません。 This answerは、CountdownLatch
の例を示していますが、新しい作業が要求されることはありません。
あなたの*クライアント*はあなたの*クライアント*ではなく、*責任を負わせますか?安全な同時アクセスが必要な場合は、他の世界と同様にロックを解除してください。スレッドセーフな 'Dispose'は便利ですが、これは簡単な' Interlocked.CompareExchange'で実現できます。 *他の*操作に関して処理をスレッドセーフにすることは珍しいことです。通常のアプローチは、 'Dispose'が呼び出された瞬間から*将来の操作でオブジェクトを利用できないものとして通知し、まだ進行中の作業を気にかけないようにすることです。 –
"[...]' _stopping'は設定されていません[...] "待っているループの前に値を割り当てるのはなぜですか? – Sidewinder94
私は上記を書きましたが、それが同じトラップに落ちると思った後、最初に設定することについて考えました。なぜですか?私はこれをこのように受け継いだので、私はそれを修正するために何ができるかを見極めています。 – pinkfloydx33