跟踪IDisposable的并发对象访问

时间:2016-10-28 14:27:29

标签: c# multithreading

我有一个IDisposable对象,可以在多个线程之间访问。我试图找出一种方法来跟踪对象是否正在使用"在进行任何清理之前。换句话说,我需要保留某种引用计数来指示存在正在运行的方法(它们在完成时递减),以便Dispose方法不会继续直到它们全部完成(或者在一些超时之后)通过)。但我还需要确保在输入Dispose之后,以后对Method的任何调用都会失败。

类似的东西:

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

但是这不会起作用,因为Method()可能会再次被调用而_stopping尚未设置,但Dispose会继续,其他所有内容都会失效。

我可以在这里使用特定的模式,还是可以用一些框架类来解决这个问题?基本上是一些双向信号告诉Dispose没有任何事情正在进行中,因此它在向Method发信号通知它应该失败的过程中表现良好。

我找到了CountdownEvent,但我不知道如何在这里使用它。 This answer显示示例CountdownLatch,但它不会阻止请求新作品。

1 个答案:

答案 0 :(得分:0)

没有。只要对Dispose方法负责&#34;追踪&#34;消耗该类的所有实例。班上的消费者需要处理他们的清理并妥善处理。

如果可以通过多个类多次调用Dispose,那么您只是发现了代码味道。只有一个班级应该调用处理方法;并且该类应该使用Dispose方法跟踪类的使用者。

防止多次调用dispose的常见模式是设置一个标志,类似于现在的标志。根据需要使用ObjectDisposedException

private bool _zombified;

public void Method()
{
    if (_zombified)
        throw new ObjectDisposedException();

    // method's logic
}


public void Dispose
{
    if(_zombified)
    {
        return;
    }

    _zombified = true;

    // perform clean-up
}