C# 中的可升级读卡器锁

发布于 2024-12-06 08:52:27 字数 372 浏览 0 评论 0原文

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

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

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

I have a dictionary that is shared among number of threads. Every thread reads specific value from the dictionary according to a given key, but - if the key does not exist in the dictionary the thread need to add it to the dictionary.
To solve the sync problem, I though to use ReaderWriterLockSlim class which basically gives me readers-writers lock synchronization (meaning readers can run in parallel but only one writer at a time...) but adds upgrade option for a reader. Using the upgrade option I can test whether a given key is already in the dictionary and if not - upgrade the lock and write it, promising only one addition for every key.

My problem is that I cant create two upgradeable locks at a time - meaning this solution is no good... :(

Can somebody please explain to me why Microsoft chose to implement the upgradable lock this way (that I cant have more than one upgradable lock at a time...), and give me any idea how can I implement the upgradable lock by myself \ give me another idea to sync my shared dictionary?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

可爱咩 2024-12-13 08:52:27

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

If you are using .NET 4.0 why not use the ConcurrentDictionary

雨夜星沙 2024-12-13 08:52:27

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

当没有可升级锁时,这正是您必须执行的操作。

I have no idea why ReaderWriterLockSlim was implemented in that way. I suspect there are good reasons.

Why not just use ConcurrentDictionary? Then you don't have to worry about explicit locking.

That said, I don't see where having multiple upgradable reader locks would help you. Consider the following scenario:

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

In order to prevent Thread1 from overwriting what Thread2 did, you'd have to write this logic:

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

Which is exactly what you have to do when there are no upgradeable locks.

檐上三寸雪 2024-12-13 08:52:27

UpgradeableReadLock 的存在使得您不必在获取写锁之前释放读锁。它允许您执行此操作:

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

而不是因为

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

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

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

UpgradeableReadLock exists so you do not have to release your read lock prior to acquiring a write lock. It lets you do this:

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

instead of

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

As it is a ReaderWriter lock, you may still only have one writer at any given time, which an upgradeable read lock enforces. This means these two aren't equivalent; the first lets other callers sneak in, but allows concurrency in the read portion.

If you have cases where you can use ReadLocks for most reads, and UpgradeableRead for data updates/inserts, this is the intent. If all of your data accesses are potential writers, then this probably doesn't work as well and you can use simple lock(object) around your writes to enforce the exclusive access when adding/updating.

守望孤独 2024-12-13 08:52:27

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

示例:

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

It doesn't sound like you are perhaps using the optimal solution to this problem.

Example:

  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";
      }
  }

If you're using .NET 4, try using the ConcurrentDictionary class that others have mentioned.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文