What is the correct way of adding thread-safety to an IDisposable object?

I tend to use an integer rather than a boolean as your field for storing the disposed status, because then you can use the thread-safe Interlocked class to test if Dispose has already been called.

Something like this:

private int _disposeCount;

public void Dispose()
{
    if (Interlocked.Increment(ref _disposeCount) == 1)
    {
        // disposal code here
    }
}

This ensures that the disposal code is called only once not matter how many times the method is called, and is totally thread safe.

Then each method can quite simply use call this method as a barrier check:

private void ThrowIfDisposed()
{
   if (_disposeCount > 0) throw new ObjectDisposedException(GetType().Name);
}

With regard to synchronising every method – are you saying a simple barrier check won’t do – that you want to stop other threads that might be already executing code in the instance. This is a more complex problem. I don’t know what your code is doing, but consider if you really need that – will a simple barrier check not do?

If you just meant with regard to the disposed check itself – my example above is fine.

EDIT: to answer the comment “What’s the difference between this and a volatile bool flag? It’s slightly confusing to have a field named somethingCount and allow it to hold 0 and 1 values only”

Volatile is related to ensuring the read or write operation operation is atomic and safe. It doesn’t make the process of assigning and checking a value thread safe. So, for instance, the following is not thread safe despite the volatile:

private volatile bool _disposed;

public void Dispose()
{
    if (!_disposed)
    {
        _disposed = true

        // disposal code here
    }
}

The problem here is that if two threads were close together, the first could check _disposed, read false, enter the code block and get switched out before setting _disposed to true. The second then checks _disposed, sees false and also enters the code block.

Using Interlocked ensures both the assignment and subsequent read are a single atomic operation.

Leave a Comment