为什么共享锁只能持有一把可升级锁
Why only one upgradable lock can be held with shared locks
The boost documentation for upgradable and shared locks 表示当持有共享锁时,只有一个其他线程可以获得可升级的锁。因此,如果其他线程在共享锁与可升级锁一起持有时尝试获取可升级锁,它们将阻塞。
当一个以上的线程与一个(或多个共享锁)一起获取可升级锁时,是否存在我遗漏的死锁可能性?或者这只是一个合乎逻辑的要求(所以是 "should not do this" 之类的事情)?
请注意,我不是在谈论独占锁定状态。只有可升级的锁定状态。如果可升级锁与其他共享锁一起持有,则它本质上是一个 READ 锁。那为什么不能把两把升级锁抱在一起呢?
Is there some deadlock possibility that I am missing when more than one thread acquire upgradable locks
TL;DR 是的,有。
along with one (or more than one shared lock)
这并没有真正影响死锁的可能性。与独占锁相比,在可升级锁存在时允许共享锁只是可升级锁的一个特性。
让我们先考虑一下可升级锁可以用来做什么。我们想象一下这样的情况:
- 多个写入线程必须检查条件(读取操作),然后根据该条件修改状态
- 检查条件很昂贵
- 很少满足条件。
- 其他线程也读取状态。
现在,让我们考虑一下,我们只有 reader(共享)/写入(独占)锁,没有可升级的锁:
- Writer 获取独占锁,并开始检查条件
- 其他线程必须阻塞,而昂贵的检查操作是 运行 - 即使他们只需要读取。
检查-写入周期的读取部分甚至会阻塞读取线程,这可能被认为是一个缺点。所以,让我们考虑一个替代方案:
- Writer 获取共享锁,并开始检查条件
- 其他线程也可能使用共享锁
- Writer 已检查条件,并释放读锁
- 条件已满足,writer 现在尝试获取独占锁以继续
在 3. 和 4. 之间,不止一个作者可能已经完成了状态检查——因为他们可以同时检查——现在正在竞相获取独占锁。只有一个可以获胜,其他人必须阻止。在他们阻塞的同时,获胜者正在修改状态。
在这种情况下,等待获取独占锁的写入者不能再假设他们检查的条件是有效的!另一个作者可能先于他们抢到了锁,现在状态已经被修改了。他们可以忽略这一点,这可能会导致未定义的行为,具体取决于与条件和修改的关系。或者,他们可以在获得独占锁时再次检查条件,这使我们回到第一种方法,除了可能由于竞争而无用的冗余检查。无论哪种方式,这种方法都比第一种方法差。
上述情况的解决方案是特权读取(可升级)锁:
- 编写器获取特权锁,并开始检查条件
- 其他线程可能会使用共享锁
- Writer 已检查满足的条件,并升级为独占锁(必须阻塞直到其他锁被释放)
让我们考虑一种情况,多个写入者被授予特权锁。他们可以同时检查昂贵的条件,这很好,但他们仍然需要争先恐后地升级锁。这次竞争导致了死锁,因为每个writer都持有读锁,等待所有的读锁释放后才能升级。
如果可升级锁相对于其他可升级锁是独占的,则不会发生死锁,并且昂贵的检查和修改之间不存在竞争,但 reader 个线程可能仍会运行在笔者检查的时候。
The boost documentation for upgradable and shared locks 表示当持有共享锁时,只有一个其他线程可以获得可升级的锁。因此,如果其他线程在共享锁与可升级锁一起持有时尝试获取可升级锁,它们将阻塞。
当一个以上的线程与一个(或多个共享锁)一起获取可升级锁时,是否存在我遗漏的死锁可能性?或者这只是一个合乎逻辑的要求(所以是 "should not do this" 之类的事情)?
请注意,我不是在谈论独占锁定状态。只有可升级的锁定状态。如果可升级锁与其他共享锁一起持有,则它本质上是一个 READ 锁。那为什么不能把两把升级锁抱在一起呢?
Is there some deadlock possibility that I am missing when more than one thread acquire upgradable locks
TL;DR 是的,有。
along with one (or more than one shared lock)
这并没有真正影响死锁的可能性。与独占锁相比,在可升级锁存在时允许共享锁只是可升级锁的一个特性。
让我们先考虑一下可升级锁可以用来做什么。我们想象一下这样的情况:
- 多个写入线程必须检查条件(读取操作),然后根据该条件修改状态
- 检查条件很昂贵
- 很少满足条件。
- 其他线程也读取状态。
现在,让我们考虑一下,我们只有 reader(共享)/写入(独占)锁,没有可升级的锁:
- Writer 获取独占锁,并开始检查条件
- 其他线程必须阻塞,而昂贵的检查操作是 运行 - 即使他们只需要读取。
检查-写入周期的读取部分甚至会阻塞读取线程,这可能被认为是一个缺点。所以,让我们考虑一个替代方案:
- Writer 获取共享锁,并开始检查条件
- 其他线程也可能使用共享锁
- Writer 已检查条件,并释放读锁
- 条件已满足,writer 现在尝试获取独占锁以继续
在 3. 和 4. 之间,不止一个作者可能已经完成了状态检查——因为他们可以同时检查——现在正在竞相获取独占锁。只有一个可以获胜,其他人必须阻止。在他们阻塞的同时,获胜者正在修改状态。
在这种情况下,等待获取独占锁的写入者不能再假设他们检查的条件是有效的!另一个作者可能先于他们抢到了锁,现在状态已经被修改了。他们可以忽略这一点,这可能会导致未定义的行为,具体取决于与条件和修改的关系。或者,他们可以在获得独占锁时再次检查条件,这使我们回到第一种方法,除了可能由于竞争而无用的冗余检查。无论哪种方式,这种方法都比第一种方法差。
上述情况的解决方案是特权读取(可升级)锁:
- 编写器获取特权锁,并开始检查条件
- 其他线程可能会使用共享锁
- Writer 已检查满足的条件,并升级为独占锁(必须阻塞直到其他锁被释放)
让我们考虑一种情况,多个写入者被授予特权锁。他们可以同时检查昂贵的条件,这很好,但他们仍然需要争先恐后地升级锁。这次竞争导致了死锁,因为每个writer都持有读锁,等待所有的读锁释放后才能升级。
如果可升级锁相对于其他可升级锁是独占的,则不会发生死锁,并且昂贵的检查和修改之间不存在竞争,但 reader 个线程可能仍会运行在笔者检查的时候。