尝试使用嵌套锁来保持并发字典的清洁。

huangapple go评论56阅读模式
英文:

Trying to keep clean the concurrent dictionary with nested locks

问题

我必须根据它们的键(UID)锁定对象,执行一些操作然后解锁。我想保持我的字典清晰。
因此,在这里我使用嵌套锁定。第一个是锁定整个字典,以安全地执行RemoveLock(uid)。第二个是锁定一个对象来执行操作。
我的问题是,在这个代码中我应该担心死锁吗?

英文:

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.

答案1

得分: 1

没有,这段代码不会发生死锁。锁总是以相同的顺序获取,首先是 _listLock,然后是字典中的一个对象,因此不会发生Dijkstra在他著名的哲学家就餐问题中描述的死锁条件。

但是,使用锁对象来保护 ConcurrentDictionary<K,V> 与使用 ConcurrentDictionary<K,V> 的初衷相违背。与使用普通的 Dictionary<K,V> 相比,你什么都没有,除了额外的开销和内存分配。此外,持有 _listLock 时调用 body 是糟糕的做法。这意味着所有 body 调用都会串行化,从而破坏了使用任何类型的字典,无论是并发的还是不并发的,的初衷。

英文:

> My question is should I fear deadlock in this code?

No, there is no risk of deadlock. The locks are always acquired in the same order, first the _listLock and 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 a ConcurrentDictionary<K,V> in the first place. You get nothing compared to using a normal Dictionary<K,V>, apart from extra overhead and memory allocations. Also calling the body while holding the _listLock is terrible. It means that all the body invocations will be serialized, defeating the purpose of using any kind of dictionary, concurrent or not.

huangapple
  • 本文由 发表于 2023年6月9日 04:57:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/76435647.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定