Implementing a thread safe dictionary
I have been implementing a simple and easy to use IoC library: I need a simple solution and big frameworks like Spring.net offer way too much stuff (even Autofac is getting huge). My implementation is composed of some basic container, some simple instantiation logic and some stuff to do automatic property injection. Nothing more.
In order to keep a collection of all singleton instances registered in the IoC container, I needed a thread safe dictionary implementation. There are a lot of discussions about how to do it right: the agreed point is that it isn't simple, mainly because you're working at the wrong level of abstraction.
Either you get a lock on each single IDictonary method, that would result in tons of locking with potentially incoherent results between one call and the other. Or you expose a more complex interface, like they did with ASP.NET MVC's RouteTable collection, and leave locking to the user.
I decided to do something in between, using ReaderWriterLockSlim from .NET 3.5 instead of a simple lock{} and writing a fine grained IDictionary implementation while also exposing some high level methods to obtain coherent and really thread safe results.
Here's how the implementation looks:
public class SafeDictionary<TId, TValue> : IDictionary<TId, TValue>
where TValue : class {
ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
Dictionary<TId, TValue> _dict = new Dictionary<TId, TValue>();
#region Helpers
private void DoWithReaderLock(Action action) {
_lock.EnterReadLock();
try {
action();
}
finally {
_lock.ExitReadLock();
}
}
private void DoWithWriterLock(Action action) {
_lock.EnterWriteLock();
try {
action();
}
finally {
_lock.ExitWriteLock();
}
}
#endregion
The thread safe dictionary wraps a lock and the real collection. All access to the underlying dictionary goes through the two helper methods: they get a read/write lock (without timeout) and then execute a delegate that will do the actual work.
The code for the IDictionary methods look like this:
public void Add(TId key, TValue value) {
DoWithWriterLock(() => {
_dict.Add(key, value);
});
}
public bool ContainsKey(TId key) {
bool ret = false;
DoWithReaderLock(() => {
ret = _dict.ContainsKey(key);
});
return ret;
}
public ICollection Keys {
get {
TId[] ret = null;
DoWithReaderLock(() => {
ret = (from ele in _dict
select ele.Key).ToArray();
});
return ret;
}
}
//...
Enumeration is a bit more difficult, but essentially works by acquiring a read lock and then getting an enumerator to the original collection. The enumerator and the lock are then given to a custom enumerator that uses its IDisposable interface to release the lock. This way the user can enumerate the collection without acquiring an exclusive lock and the read lock is released correctly after use.
Same thing goes for some higher level access methods: GetExclusiveDictionary returns a locked dictionary implementation that keeps a write lock on the collection until it is disposed. Other methods take a delegate that operates on the original collection directly after acquiring a lock: this way the user can work with the collection for some time and obtain coherent return values.
public LockedDictionary<TId, TValue> GetExclusiveDictionary() {
_lock.EnterWriteLock();
return new LockedDictionary<TId, TValue>(_dict, _lock);
}
public void ManipulateWithWriteLock(Action<IDictionary<TId, TValue>> operation) {
DoWithWriterLock(() => {
operation(_dict);
});
}
public void ManipulateWithReadLock(Action<IDictionary<TId, TValue>> operation) {
DoWithReaderLock(() => {
operation(_dict);
});
}
Source code
You can get the SafeDictionary source code if you want. I cannot guarantee it works, but it appears to be working correctly in my tests. Let me know in case your computer blows up when you use it! ![]()




Do you plan to share the IoC library?