正确的锁定模式

时间:2018-02-13 09:30:39

标签: c# algorithm design-patterns locking

我在C#中遇到了一个锁问题(但无论语言如何,这都是算法问题)。

当我输入一个方法时,我对一个对象进行读锁定。但是如果给定的对象为null(未初始化),我需要初始化它。所以,我需要对它进行写锁定。但是,问题是我已经处于读取锁定区域。

例如:

 public string LocalUid
        {
            get
            {
                        using (new ReadLock(MongoDBConnector.adminLock))
                        { 
                            MongoClient mongo = MongoDBConnector.GetAdminClient();
                           // Do something...
                        }
                    }
                    return localUid;
                }
                return null;
            }
        }

并且GetAdminClient方法是:

public static MongoClient GetAdminClient()
        {
            if (adminClient == null)
            {
                using (new WriteLock(adminLock))
                {
                    if (adminClient == null) // Double check locking pattern
                    {
                        adminClient = CreateAdminClient();
                    }
                }
            }
            return adminClient;
        }

因此我们清楚地看到在一个解锁区域中询问了writelock :(

这种情况的任何想法/最佳做法?

1 个答案:

答案 0 :(得分:1)

这是一种称为锁定升级的常见模式。您必须非常小心,以避免因锁升级导致的死锁:

Thread A acquires read lock on Resource X.
Thread B acquires read lock on Resource X (this is allowed because Thread A only has a read lock).
Thread A wants to escalate its read lock to a write lock on Resource X, but it has to wait for Thread B to first release its read lock.
Thread B wants to escalate its read lock to a write lock on Resource X, but it has to wait for Thread A to first release its read lock.
Threads A and B are now deadlocked.

这种类型的死锁可以通过开始写入锁来避免,即,如果读取结果可能要求您稍后进行写锁定,则在读取时执行写锁定。