使用upgrade_lock进行饥饿

时间:2014-02-14 07:50:46

标签: multithreading boost mutex

我正在尝试使用Boost upgrade_lock(使用this example,但我遇到了饥饿问题。

我实际上正在使用this post中的代码,但我想要一个最新的讨论。我在 WorkerKiller 之后运行了400个线程。我遇到了与 anoneironaut 完全相同的问题,这是提到的帖子的作者。

我已经看过 Howard Hinnant 的命题,但我真的不想包含更多的外部代码(而且我现在无法让他编译)并在6个月之后发布评论声明“ Boost现在使用公平的实施”(12月3日')。

Boost 1.55 documentation表示:

Note the the lack of reader-writer priority policies in shared_mutex. This is 
due to an algorithm credited to Alexander Terekhov which lets the OS decide 
which thread is the next to get the lock without caring whether a unique lock or 
shared lock is being sought. This results in a complete lack of reader or writer
starvation. It is simply fair.". 

归功于 Alexander Terekhov 的算法是 Howard Hinnant 所讨论的算法,所以我希望1.55提升实现的行为与Howard Hinnant的答案相似,事实并非如此。它的行为与问题完全相同。

为什么我的 WorkerKiller 遭受饥饿?

更新:在this code上观察到:

  • Debian x64,Boost 1.55(Debian版本和源代码编译),包含clang ++和g ++
  • Ubuntu x64,Boost 1.54,同时包含clang ++(3.4-1ubuntu1)和g ++(4.8.1-10ubuntu9)

1 个答案:

答案 0 :(得分:2)

这是一个微妙的问题。差异涉及共享和可升级所有权的概念,以及它们在Boost中的实现。

让我们首先了解共享所有权和可升级所有权的概念。 对于SharedLockable,线程必须事先决定是要更改对象(需要独占所有权)还是仅从中读取(共享所有权足够)。如果具有共享所有权的线程决定它想要更改对象,则它首先必须释放其对象上的共享锁,然后构造一个新的独占锁。在这两个步骤之间,线程在对象上根本没有锁。尝试从已经拥有共享锁的线程构造独占锁将会死锁,因为独占锁构造函数将阻塞,直到所有共享锁都被释放。

UpgradeLockable通过允许将共享锁升级到独占锁而不释放来克服此限制。也就是说,线程始终在互斥锁上保持活动锁定,同时禁止其他线程获得排它锁。除此之外,UpgradeLockable仍然允许来自SharedLockable的所有操作,前者的概念是后者的超集。 question you linked to仅关注SharedLockable概念。

Boost所规定的概念都不要求实施是公平的。但是,shared_mutex,这是Boost对SharedLockable的最小实现,确实可以提供您问题中引用的公平性保证。请注意,这是该概念实际需要的附加保证

不幸的是,可升级所有权的最小实施upgrade_mutex并没有给予这个额外的保证。它仍然将共享所有权概念作为可升级所有权的要求实现,但由于合规性实施不需要公平性,因此它们不提供它。

作为pointed out by Howard in the comments,Terekhov的算法可以通过简单的调整来处理可升级的锁,只是Boost实现目前不支持这种算法。