【问题标题】:Why only one upgradable lock can be held with shared locks为什么共享锁只能持有一个可升级锁
【发布时间】:2016-07-29 04:30:52
【问题描述】:

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

当多个线程与一个(或多个共享锁)一起获取可升级锁时,我是否会遗漏一些死锁的可能性?或者这只是一个合乎逻辑的要求(所以“不应该这样做”之类的事情)?

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

【问题讨论】:

  • @downvoter 请解释我可以做些什么来改善这个问题?
  • 我会在发现我提出的不适合 SO 的问题后立即删除该问题?
  • 这是一个显而易见的问题吗?有人能解释一下我得到这么多反对票的原因吗?
  • 关于这个问题有这样的争议。

标签: c++ multithreading c++11 boost mutex


【解决方案1】:

当多个线程获取可升级锁时,我是否会丢失一些死锁的可能性

TL;DR 是的,有。

连同一个(或多个共享锁)

这并不会真正影响死锁的可能性。与独占锁相比,在可升级锁存在时允许共享锁只是可升级锁的一个特性。


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

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

现在,让我们考虑一下我们只有读取器(共享)/写入器(独占)锁,没有可升级锁:

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

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

  1. Writer 获取共享锁,并开始检查条件
  2. 其他线程也可以使用共享锁
  3. Writer 已检查条件,并释放读锁
  4. 条件已满足,写入器现在尝试获取排他锁以继续

在 3. 和 4. 之间,可能不止一位作者已经完成了状态检查——因为他们可以同时检查——并且现在正在竞相获取排他锁。只有一个人可以赢,其他人必须阻止。当他们阻塞时,获胜者正在修改状态。

在这种情况下,等待获取排他锁的编写者不能再假设他们检查的条件是有效的!另一个作家可能已经抢到了他们之前的锁,并且现在已经修改了状态。他们可以忽略这一点,这可能会导致不确定的行为,具体取决于与条件和修改的关系。或者,他们可以在获得排他锁时再次检查条件,这使我们回到第一种方法,除了由于竞争而无用的潜在冗余检查。无论哪种方式,这种方法都比第一种方法差。


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

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

让我们考虑一个情况,多个写入者被授予特权锁。他们可以同时检查昂贵的条件,这很好,但他们仍然需要升级锁。这一次,竞争导致死锁,因为每个写入者都持有读锁,并等待所有读锁释放后才能升级。

如果可升级锁相对于其他可升级锁是独占的,那么这种死锁就不会发生,昂贵的检查和修改之间不存在竞争,但读取器线程仍然可以在写入器检查时运行。

【讨论】:

  • “如果可升级锁对其他可升级锁是独占的”是什么意思?您的意思是说只有一个可升级锁与其他读卡器锁一起存在?
  • @Curious 是的。我现在在该句子中添加了“关于”。
  • 解决方案非常简单!不知道为什么我不能早点想到..
猜你喜欢
  • 2014-08-11
  • 1970-01-01
  • 2012-08-03
  • 1970-01-01
  • 2019-12-09
  • 2013-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多