公平可重入锁 C++

5
我正在处理一个程序,在其中一个线程比另一个线程处理更多的工作时,会导致饥饿问题。关键部分由一个可重入 QMutex 保护,但这个锁不公平。
在 Java 中,你可以为锁指定一个公平参数。C++(或 boost 库)有公平的可重入锁吗?最好是 C++11 及以上版本。
之前我做过一些研究,boost 中有 shared_lock,但我不需要读写锁,只需要一个锁来保证每个线程进入关键部分的机会相等。
非常感谢。

1
自 C++11 开始,有 std::mutexstd::lock_guard<std::mutex>,但它们不保证公平。我相信 MSVC CRT 实现使用等待队列,因此在该平台上可能是公平的。 - Cameron
是的,但我需要一个公平锁... - Veaceslav
不要使用C++中通常不可用的公平性参数,您可能会发现通过优先级排队工作分派,以便您可以调节“重型”操作以避免饥饿,从而更好地控制情况。尽管这需要编写更多的代码,但从长远来看可能会给您带来更好的结果。 - Component 10
从操作系统的角度来看,所有线程都有类似的运行机会,因此如果您没有为线程设置不同的优先级,并且某些线程出现饥饿现象,这意味着这些线程没有被操作系统线程调度器分配足够的时间,但这种情况不应该发生。这反映了您的设计可能存在问题。 - jean
1个回答

2

C++线程原语实际上是基于Posix线程的,而Posix没有任何公平锁。然而,你的问题表明你的设计存在问题。这里有两个问题:

  1. 可重入互斥锁是问题的标志。你需要100%控制互斥锁的所有权和生命周期。如果你需要可重入互斥锁,那么意味着你的设计很松散。
  2. 你描述的线程饥饿是线程通信设计不当的结果。如果一个线程需要在工作期间持有互斥锁,那么你实际上正在设计一个单线程系统,根本不需要任何线程。

1
嗯,原则上是这样,但通常事情并不像那么简单;-) - Cameron
@Cameron,在现实生活中是这样的。 - SergeyA
你可能对可重入性是正确的,但你对公平性和线程饥饿是错误的。即使在简单的情况下,线程也可能会饥饿。我学过并发课程,在那里广泛讨论了这个问题,现在我在实际中遇到了这个问题。太糟糕了,C++对于开发多线程程序时真正必要的东西支持不好。 - Veaceslav
@Veaceslav,你能详细解释一下吗?我想看一个例子,其中线程饥饿不是由于糟糕的设计而产生的结果。 - SergeyA
一个线程正在轮询新项目的队列。在轮询时,它会获取锁。生产者线程想要将某些东西放入队列中,但被不断轮询并抓住锁的消费者线程所饥饿。这是我解决了公平锁的Java作业之一。此外,真实案例应用程序:我们有必须串行化的sqlite访问。该程序作为批处理过程向数据库写入大量数据。而批处理过程处于活动状态时,依赖于获取数据的界面功能会受到限制。 - Veaceslav
@Veaceslav,你的例子清楚地展示了糟糕的设计。 - SergeyA

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接