c# - 可升级的readlock的优势?

标签 c# multithreading locking

我想知道使用可升级的读锁相对于执行以下步骤有什么好处:

  1. Take read lock
  2. Check condition to see if we need to take write lock
  3. Release Read Lock
  4. Take Write Lock
  5. Perform update
  6. Release Write Lock


与采取可升级的读锁相反,执行上述步骤的一个明显的缺点是,在步骤3和4之间存在一个时间窗口,其中另一个线程可以占用写锁。

除了这个优点之外,您发现在上述步骤上采取可升级的读取锁定还有哪些其他优点?

最佳答案

让我们考虑一下可以使用没有单独的“可升级读取器”的读取器-写入器锁的不同方式。

如您所指出的,在您的模式下,第3步和第4步之间存在竞争,其中另一个线程可以使用writer锁。更重要的是,在第3步和第4步之间有一个步骤,线程可以使用编写者锁并更改我们在步骤2 中观察到的状态。

因此,根据情况发生的可能性,我们有四个选择:

  • 我们坚持使用您的方法,因为这实际上是不可能的(例如,给定的状态转换在我们的应用程序中是单向的,因此一旦观察到它是永久的)。在这种情况下,尽管我们很可能已经进行了重构,以致根本不需要锁。 (单向过渡适用于无锁技术)。
  • 首先,我们只使用writer锁定,因为我们在步骤2中观察到的状态很可能会发生变化,并且浪费了使用读取器锁定检查它的时间。
  • 我们将您的步骤更改为:
  • 采取读锁
  • 检查条件以查看是否需要采取写锁定
  • 释放读取锁定
  • 取写锁
  • 重新检查条件以防万一。
  • 执行更新
  • 释放写锁定
  • 我们更改为:
  • 在支持递归的锁上获取读锁。
  • 检查是否需要执行写锁定。
  • 取得写锁定(不释放读取)。
  • 执行更新。
  • 释放写锁定。
  • 释放读取锁定。

  • 不难理解为什么4对某些人更具诱惑力,尽管很难看清它如何使死锁更容易产生。可悲的是,稍微难一点就足以让很多人看到优点而看不到缺点。

    对于没有发现它的任何人,如果两个线程具有读锁,并且其中一个升级到写锁,则它必须等待另一个线程释放读锁。但是,如果第二个线程在不释放读锁的情况下升级到写锁,则它将在第一个线程上永远等待,这将在第一个线程上永远等待。

    如上所述,哪种方法最佳取决于状态在此期间发生变化的可能性(或者,我想我们希望对此做出快速 react )。即使采用不释放升级的最后一种方法也可以在可行的代码中占有一席之地,只要只有一个线程尝试在不释放锁的情况下升级其锁即可。

    除了最后一个选项起作用的特殊情况外,其他选项之间的差异都与性能有关,而最有效的性能主要取决于重新检查状态的成本以及由于更改而中止写入的可能性同时。

    但是,请注意,所有这些操作都涉及到一个写作者锁,因此,即使确实中止了写入操作,所有这些操作都具有阻塞所有读取线程的作用。

    可升级的读锁为我们提供了中间立场,因为尽管它们阻止写锁和其他可升级的读锁,但它们不阻止读锁。尽管它们可能不是更好的读锁,但可以升级为尚未提交写入的写锁。*在决定不升级的情况下,对读线程的影响为零。

    这意味着如果线程甚至有可能决定不更改状态,则读取线程也不会受到影响,并且性能的提高肯定可以证明其使用是合理的。

    *就此而言,“读者-作家”有点用词不当,我们可以使用ReaderWriterLockSlim保护整数或对象数组,使用读取锁原子地读写单个项目,并使用写入锁进行需要读取整个数组而读取时不改变其一部分的操作。在这种情况下,这是需要独占锁的读取操作,而使用共享锁可以进行写操作。

    关于c# - 可升级的readlock的优势?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8787606/

    相关文章:

    javascript - 是否有可能两个异步 Javascript 函数实例同时执行两个代码块?

    java - 为什么 Java 8 有 Arrays.parallelSort() 但没有 Collections.parallelSort()?

    java - 我如何将 ReentrantReadWriteLock.readLock 或 ReentrantReadWriteLock.writeLock 转换为我的类对象

    c++ - std::map 是否锁定其节点以防止其他进程删除它们?

    java - 调用其condition.await时是否会释放可重入锁?

    c# - 自动生成不可变类和匹配的构建器类

    c# - 即使在使用任务时也无法等待 'Void'

    java - 原子能保证可见性吗? java

    C#继承和静态类

    c# - 对 0、1 和 2 的数组进行排序(进一步优化)