c#中可升级的阅读器锁定

本文关键字:锁定 可升级 | 更新日期: 2023-09-27 18:09:37

我有一个在多个线程之间共享的字典。每个线程根据给定的键从字典中读取特定的值,但是-如果键不存在于字典中,线程需要将其添加到字典中。
为了解决同步问题,我想使用ReaderWriterLockSlim类,它基本上为我提供了读取器-写入器锁定同步(意味着读取器可以并行运行,但一次只能运行一个写入器……),但为读取器增加了升级选项。使用升级选项,我可以测试给定的键是否已经在字典中,如果不是,升级锁并写入它,保证每个键只添加一个。

我的问题是我不能一次创建两个可升级的锁-这意味着这个解决方案不好…(

谁能给我解释一下为什么微软选择以这种方式实现可升级锁(我不能同时拥有多个可升级锁…),并给我任何想法,我如何实现我自己的可升级锁'给我另一个想法来同步我的共享字典?

c#中可升级的阅读器锁定

如果你使用的是。net 4.0,为什么不使用ConcurrentDictionary

我不知道为什么ReaderWriterLockSlim以这种方式实现。我认为有充分的理由。

为什么不直接使用ConcurrentDictionary?这样你就不用担心显式锁定了。

也就是说,我不认为拥有多个可升级的阅读器锁会有什么帮助。考虑以下场景:

Thread1 enters the lock in upgradeable mode
Thread2 enters the lock in upgradeable mode
Thread1 searches for "xyzzy" and doesn't find it
Thread2 searches for "xyzzy" and doesn't find it
Thread2 upgrades to a write lock
Thread1 waits to upgrade to a write lock
Thread2 updates and releases the lock
Thread1 acquires the write lock and overwrites what Thread2 had written

为了防止Thread1覆盖Thread2所做的,你必须写这样的逻辑:

Enter upgradable read lock
if (!dict.TryGetValue(...))
{
    Enter write lock
    if (!dict.TryGetValue(...))  // extra check required!
    {
    }
}

当没有可升级的锁时,这正是您必须做的。

UpgradeableReadLock存在,因此您不必在获得写锁之前释放读锁。它允许你这样做:

   locker.EnterUpgradeableReadLock();
   ...
   locker.EnterWriteLock(); 
   ...

代替

   locker.EnterReadLock();
   ...
   locker.ExitReadLock();
   locker.EnterWriteLock();
   ...

由于它是一个ReaderWriter锁,因此在任何给定时间您可能仍然只有一个写入器,这是可升级的读锁强制的。这意味着这两个不相等;第一个允许其他调用者潜入,但允许读部分并发。

如果你需要在大多数读操作中使用ReadLocks,在数据更新/插入操作中使用upgradeableeread,这就是目的。如果所有的数据访问都是潜在的写操作,那么这可能不太好工作,您可以在写操作周围使用简单的锁(对象)来强制添加/更新时的独占访问。

听起来您可能没有使用这个问题的最佳解决方案。

的例子:

  protected static object _lockObj = new object();
  if(_dictionary.ContainsKey(key))
  {
      return _dictionary[key];
  }
  else
  {
      lock(_lockObj)
      {
           if(_dictionary.ContainsKey(key))
              return _dictionary[key];
           _dictionary.Add(key, "someValue");
           return "someValue";
      }
  }

如果你正在使用。net 4,尝试使用其他人提到的ConcurrentDictionary类。