代码之家  ›  专栏  ›  技术社区  ›  Curious

为什么共享锁只能持有一个可升级锁

  •  6
  • Curious  · 技术社区  · 10 年前

    The boost documentation for upgradable and shared locks 表示当持有共享锁时,只有一个其他线程可以获得可升级的锁。因此,如果其他线程试图在共享锁与可升级锁同时持有时获取可升级锁,那么它们将阻塞。

    当多个线程同时获得一个(或多个共享锁)可升级锁时,是否存在死锁丢失的可能性?或者这只是一个逻辑要求(所以“不应该这样做”之类的事情)?

    请注意,我并不是在谈论独占锁定状态。只有可升级的锁定状态。如果一个可升级锁与其他共享锁一起持有,那么它本质上就是一个READ锁。那么为什么两个可升级的锁不能连在一起呢?

    1 回复  |  直到 10 年前
        1
  •  5
  •   eerorika    10 年前

    当多个线程获取可升级锁时,是否存在死锁丢失的可能性

    以及一个(或多个共享锁)

    这实际上并不影响死锁的可能性。与独占锁相比,在存在可升级锁时允许共享锁只是可升级锁的一个功能。


    让我们首先考虑一下可升级锁的用途。我们将设想以下情况:

    • 多个写入线程必须检查一个条件(读取操作),然后根据该条件修改状态
    • 检查条件很昂贵
    • 这种情况很少得到满足。
    • 其他线程也读取状态。

    现在,让我们考虑一下,我们只有reader(shared)/writer(exclusive)锁,没有可升级的锁:

    1. Writer接受独占锁,并开始检查条件
    2. 其他线程必须在昂贵的检查操作运行时阻塞,即使它们只需要读取。

    检查-写入周期的读取部分甚至会阻塞读取线程,这可能被认为是一个缺点。因此,让我们考虑一个替代方案:

    1. Writer获取共享锁,并开始检查条件
    2. Writer已检查条件,并释放读取锁定
    3. 条件已满足,编写器现在尝试获取独占锁以继续

    在3.到4.之间,可能有不止一个编写器完成了状态检查,因为它们可以同时进行检查,并且现在正在竞相获取独占锁。只有一个人能赢,其他人必须阻止。当他们封锁时,胜利者正在修改状态。

    在这种情况下,等待获取独占锁的编写器不能再假设他们检查的条件是有效的!另一个作者可能在他们之前抢走了锁,现在状态已经被修改。他们可以忽略这一点,这可能会导致未定义的行为,具体取决于与条件和修改的关系。或者,他们可以在获得独占锁时再次检查条件,这会使我们返回到第一种方法,除非有可能因争用而无用的冗余检查。不管怎样,这种方法都比第一种方法差。


    上述情况的解决方案是特权读取(可升级)锁:

    1. Writer获取特权锁,并开始检查条件
    2. 其他线程可能使用共享锁
    3. 编写器已检查满足的条件,并升级到独占锁(必须阻止,直到释放其他锁)