When I look through sample implementations of IDisposable
, I have not found any that are threadsafe. Why is IDisposable
not implemented for thread safety? (Instead callers have a responsibility to make sure only a single thread calls Dispose()
).
5 Answers
You should not dispose of an object until you have finished with it. If there are other threads referencing the object and there is a chance they might want to call its methods, you should not be disposing of it.
Therefore it is not neccessary for Dispose to be thread safe.

- 34,935
- 6
- 74
- 113
-
2In some cases, the preferred way (if not the only way) to force the abandonment of a blocking I/O operation is to `Dispose` the connection out from underneath it; such disposal can *only* happen from an outside thread (the blocked thread can't do anything while it's blocked). It's possible an outside thread might decide to `Dispose` the connection just as the connection is finishing up its work and the thread that had been blocked decides to `Dispose` it itself. – supercat Jun 15 '12 at 17:32
-
If there is a use-case for another thread forcing the abandonment of a blocking operation, that requires someone to write code to make it work. Surely the implementor would be wiser to implement a `ForceAbandon` method rather than abuse the semantics of `Dispose`. And if the implementor doesn't realize this is a required use-case you cannot expect `Dispose` to behave correctly either. It might, but that would just be luck. – Ben Jun 15 '12 at 18:53
-
1I've seen a number of I/O libraries in which the only cross-thread operation which is supported is killing a connection. `Dispose` seems the best fit. Also, in some cases, the most reasonable way to ensure cleanup of partially-constructed objects may involve objects which mutually dispose each other, so `Object1.Dispose` might call `Object2.Dispose`, which could in turn call `Object1.Dispose`. Guarding against that wouldn't require `Interlocked`, but it would still require a better pattern than Microsoft's. – supercat Jun 15 '12 at 19:42
-
Perhaps it's perspective but `Dispose` seems a poor fit to me. What about `Close`?. Dispose implies that there is no way to get status after the connection is cut. Second, partially constructed objects failing at all, *let alone requiring Dispose* is one of those use-cases which is only of interest in a tiny minority of cases, like checking the return of malloc vs. getting an SEGV and terminating. When it matters, it matters. But that is almost never - in most applications if you get into that situation you may as well just dump core. – Ben Jun 15 '12 at 20:14
-
To my mind, classes should have separate `Dispose` and `Close` methods is if there would be some benefit to calling `Close` even if one also calls `Dispose`. Otherwise the `Close` method is just clutter. As for failed constructors, they can occur for a number of reasons, some of which should be recoverable (e.g. trying to construct a UI object based upon information from corrupted document stored on disk). Even if an object doesn't have any weird failed-constructor corner cases of its own, an object which might be used by other objects that might should be robust in the face of such usage. – supercat Jun 15 '12 at 20:33
-
Cases like that cannot be reliably recovered. That is the point where you page/email the operator to investigate, not try to code around like you know everything that can possibly go wrong. – Ben Jun 15 '12 at 21:51
The only real benefit to a thread-safe Dispose pattern is that you could be guaranteed to get an ObjectDisposedException rather than potentially unpredictable behavior in the event of cross-thread misuse. Note that this means the pattern requires more than thread-safe Dispose; it requires that all methods which rely on the class not being Disposed interlock properly with the Disposal mechanism.
It's possible to do this, but it's a lot of effort to cover a boundary case that only occurs if there is a usage error (i.e. a bug).

- 27,329
- 4
- 56
- 102
-
About the effort involved: Could we use PostSharp to inject verification logic into every public method? The only reason why I am looking in PostSharp's direction is because I've seen other languages do this sort of thing all the time. – GregC Mar 25 '11 at 17:08
-
While there aren't a whole lot of situations where multiple threads would simultaneously discover that an object is useless, there are many situations where the last use of an object may occur asynchronously, or where the fact that one object becomes eligible for garbage collection will imply that another object, to which a strong reference still exists, has become useless. A guaranteed-threadsafe `IDisposable` would be useful in such contexts. – supercat Jun 15 '12 at 17:39
Brian Lambert wrote a blog post titled A simple and totally thread-safe implementation of IDisposable.
It contains the following implementation:
using System;
using System.Threading;
/// <summary>
/// DisposableBase class. Represents an implementation of the IDisposable interface.
/// </summary>
public abstract class DisposableBase : IDisposable
{
/// <summary>
/// A value which indicates the disposable state. 0 indicates undisposed, 1 indicates disposing
/// or disposed.
/// </summary>
private int disposableState;
/// <summary>
/// Finalizes an instance of the DisposableBase class.
/// </summary>
~DisposableBase()
{
// The destructor has been called as a result of finalization, indicating that the object
// was not disposed of using the Dispose() method. In this case, call the DisposeResources
// method with the disposeManagedResources flag set to false, indicating that derived classes
// may only release unmanaged resources.
this.DisposeResources(false);
}
/// <summary>
/// Gets a value indicating whether the object is undisposed.
/// </summary>
public bool IsUndisposed
{
get
{
return Thread.VolatileRead(ref this.disposableState) == 0;
}
}
#region IDisposable Members
/// <summary>
/// Performs application-defined tasks associated with disposing of resources.
/// </summary>
public void Dispose()
{
// Attempt to move the disposable state from 0 to 1. If successful, we can be assured that
// this thread is the first thread to do so, and can safely dispose of the object.
if (Interlocked.CompareExchange(ref this.disposableState, 1, 0) == 0)
{
// Call the DisposeResources method with the disposeManagedResources flag set to true, indicating
// that derived classes may release unmanaged resources and dispose of managed resources.
this.DisposeResources(true);
// Suppress finalization of this object (remove it from the finalization queue and
// prevent the destructor from being called).
GC.SuppressFinalize(this);
}
}
#endregion IDisposable Members
/// <summary>
/// Dispose resources. Override this method in derived classes. Unmanaged resources should always be released
/// when this method is called. Managed resources may only be disposed of if disposeManagedResources is true.
/// </summary>
/// <param name="disposeManagedResources">A value which indicates whether managed resources may be disposed of.</param>
protected abstract void DisposeResources(bool disposeManagedResources);
}
However the absolute and complete totality is disputed a bit in the comments, both on the blog and here.

- 5,519
- 3
- 29
- 51
-
3@Hans: It is not fundamentally wrong; it is entirely possible that multiple threads wish to negotiate amongst themselves who gets to dispose the object when they are all done with it at the same time. **That negotiation protocol has to be made out of threadsafe parts.** Brian's blog is not "drivel". – Eric Lippert Mar 14 '11 at 14:55
-
1This is not truly thread-safe, as it does not properly address how the other method calls on the class must behave. If you really want to have thread-safety on Dispose, the easiest way is to wrap the entire Dispose method in a lock and use the same lock around every public method and throw ObjectDisposedException if already disposed. If you need to allow methods to execute in parallel besides the Dispose method, you can use a MultiRead/SingleWrite pattern, with Dispose being the 'Write' operation. – Dan Bryant Mar 14 '11 at 14:56
-
@Eric: if this negotiation is implemented properly then it doesn't require the IDisposable implementation to be thread-safe. The negotiation needs to be. I didn't assert that Brian's blog is drivel btw. Sorry to offend you. – Hans Passant Mar 14 '11 at 14:59
-
3@Hans I don't see any other way to read your initial comment. What other drivel is 'this drivel'? – bmargulies Mar 14 '11 at 15:24
-
@bmar - please make your point by addressing the technical merit of the linked blog post. I'd love to see an answer in this question that explains why it is useful and will happily excise my comment. My perceived opinion about somebody's blog is unstated and completely irrelevant to this question. – Hans Passant Mar 14 '11 at 15:41
-
The only classes that should have finalizers are those whose purpose *centers around* the finalization of a single entity, or those whose finalizer exists for logging rather than cleanup. Designing classes to handle a mixture of managed resources and unmanaged resources is almost always a mistake. Also, while it's rare for a finalizer to try to run at the same time as Dispose, it's possible for an object to die and be resurrected without its knowledge, which could cause such surprise concurrent execution. – supercat Mar 14 '11 at 16:22
-
Also, your method is only as thread-safe as the underlying DisposeResources function. Many of the circumstances which would result in multiple threads trying to use Dispose could also result in a thread trying to Dispose an object another thread is using. This may be intended behavior (e.g. if one thread is doing a blocking operation on a hardware device, disposing the device from another thread may be the preferred way of aborting it) but is only thread-safe if the underlying implementation is. – supercat Mar 14 '11 at 16:28
-
While this link is helpful it would be great if you fleshed the answer out rather than just pointing somewhere. for more info "Are answers that just contain links elsewhere really “good answers”? http://meta.stackexchange.com/a/8259 – Simon Jul 06 '13 at 13:18
I'm not sure why Microsoft doesn't use an interlocked Disposing flag in the non-virtual dispose method (with the intention that a finalizer--if any--should use the same flag). Situations where multiple threads might attempt to dispose an object are rare, but it's not forbidden. It could occur, for example, with objects that are supposed to perform some asynchronous task and clean up after themselves, but which can be killed off early if necessary. Object disposal should not occur often enough for an Interlocked.Exchange to have any meaningful performance cost.
On the other hand, it's important to note that while protecting Dispose against multiple invocations is IMHO a wise policy, it is not sufficient to make Dispose really be thread-safe. It is also necessary to ensure that calling Dispose on an object which is in use will leave things in a good state. Sometimes the best pattern for this is to have dispose set a "KillMeNow" flag, and then in a block guarded by Monitor.TryEnter, Dispose the object. Every routine (other than Dispose) which uses the object must acquire the lock during operation, but test both before acquiring and after releasing the lock to see if KillMeNow is set; if so, do a Monitor.TryEnter and perform the dispose logic.
A bigger problem with making a thread-safe IDisposable is the fact that Microsoft does not specify that an event's RemoveHandler method must be thread-safe without risk of deadlock. It is frequently necessary for a IDisposable.Dispose to remove event handlers; without a guaranteed-thread-safe way of doing that, it's almost impossible to write a thread-safe Dispose.

- 77,689
- 9
- 166
- 211
Because they are wrong and lazy, often dismissed as "edge cases" or "not worth the overhead" of being correct.
Use a reader/writer lock to synchronize a disposable class. The thing you're protecting from concurrent writes is the "disposed" state. All methods simply acquire a read lock to use the class, which guarantees they're not disposed mid-call. Because multiple readers are supported, methods do not block each other. The "dispose" method should acquire the writer lock to perform the cleanup, guaranteeing it doesn't run concurrently with any other method, or itself.
This provides complete thread-safety for the dispose method and all other methods in the class. Disposal logic will not run while normal logic runs (and vice versa), and will also not run concurrently with itself.
The reader-writer lock you use should support async, so you can use async code. As a bonus, async locks usually do not support re-entrantrancy. This is good, because you would not want one method calling another anyway, since a 'writer' lock could happen between the two read lock acquisition calls and prevent the second read lock from being taken out indefinitely (deadlock).
If you're willing to go with the "use the class correctly and don't dispose until you're sure you're done with it" line of thought, then this is all just extra overhead. However, I believe it's the only truly correct, full thread-safe approach.

- 18,766
- 21
- 107
- 173