3

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

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

有人可以向我解释为什么微软选择以这种方式实现可升级锁(我一次不能拥有多个可升级锁......),并告诉我如何自己实现可升级锁\给同步我的共享字典的另一个想法?

4

4 回答 4

8

如果您使用的是 .NET 4.0,为什么不使用ConcurrentDictionary

于 2011-09-26T20:05:05.327 回答
4

我不知道为什么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!
    {
    }
}

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

于 2011-09-26T20:05:39.403 回答
1

UpgradeableReadLock 存在,因此您不必在获取写锁之前释放您的读锁。它可以让你这样做:

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

代替

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

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

如果您可以将 ReadLocks 用于大多数读取,而将 UpgradeableRead 用于数据更新/插入,这就是目的。如果您所有的数据访问都是潜在的写入者,那么这可能效果不佳,您可以在写入周围使用简单的锁(对象)来在添加/更新时强制执行独占访问。

于 2011-09-26T20:14:27.123 回答
-2

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

例子:

  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 类。

于 2011-09-26T20:06:40.463 回答