I have to lock objects by their keys (UIDs), do some staff and unlock. And I want to keep my dictionary clear. So here I use nested lock. The first is locking the whole dictionary just to safely perform RemoveLock(uid) at the end. And the second is locking an object to do stuff. My question is should i fear deadlock in this code?
private static readonly ConcurrentDictionary<Guid, object> _lockDict = new ConcurrentDictionary<Guid, object>();
private static object _listLock;
public static void RunWithLock(Guid uid, Action body)
{
lock (_listLock)
{
var obj = GetLock(uid);
lock (obj)
{
body();
}
RemoveLock(uid);
}
}
public static void RemoveLock(Guid uid)
{
_lockDict.TryRemove(uid, out _);
}
public static object GetLock(Guid uid)
{
return _lockDict.GetOrAdd(uid, s => new object());
}
Tried to run it, didn't get any deadlocks. But thousands of objects processing every minute can make it deadlock.
No, there is no risk of deadlock. The locks are always acquired in the same order, first the
_listLockand then one of the objects in the dictionary, so the deadlock condition that is described by Dijkstra in his famous Dining philosophers problem cannot occur.That said, protecting a
ConcurrentDictionary<K,V>with a locker object defeats the purpose of using aConcurrentDictionary<K,V>in the first place. You get nothing compared to using a normalDictionary<K,V>, apart from extra overhead and memory allocations. Also calling thebodywhile holding the_listLockis terrible. It means that all thebodyinvocations will be serialized, defeating the purpose of using any kind of dictionary, concurrent or not.