如何在pthread中的读写锁中防止写入者饥饿?

37

我对在*nix系统上(例如Linux)使用POSIX Pthreads中的读写锁有一些问题。

我想知道读写锁的默认偏好是什么,即它是更倾向于读操作还是写操作?它是否提供一些API来更改这种默认行为。

POSIX Pthreads是否提供了一些API,以便我们可以更改pthread_rwlock_t以防止写入进程饥饿?根据我所读到的(如果我错了,请纠正我),默认实现是偏向于读线程的,因此写线程可能会遇到饥饿问题。

我已经阅读了David Butenhof的《Programming with Posix threads》一书中的读写锁样例实现。

我想知道posix pthreads如何处理写线程饥饿问题?是否有一些api可以使用以设置读写锁的属性,从而防止写入饥饿(我从未听说过)?还是用户必须处理这个问题?

如果您认为答案是与实现相关的,则请给我一个关于Linux中如何完成的示例,因为这就是我正在寻找的内容。

请注意,我只需要*nix系统的解决方案。不要认为我粗鲁,但是发布一些Windows特定的代码对我来说是无用的。

感谢您所有人的帮助和耐心:)


使用互斥锁而不是读写锁将避免此问题。如果争用较低,在某些实现中(例如从互斥锁和条件变量构造读写锁的实现),它也更快。 - jilles
1个回答

54

这确实取决于实现方式 - 因此,既然您特别提到了Linux,我的评论是针对当前NPTL pthreads的实现,这是现代glibc中使用的。

这里有两个相关但分开的问题。首先,有这种情况:

  • 当前持有读锁并等待写者。新线程尝试获取读锁。

默认操作是允许读者继续进行 - 实际上通过跳过作者来“插队”。但是,您可以覆盖此行为。如果您使用pthread_rwlockattr_setkind_np()函数在传递给pthread_rwlock_init()attr上设置PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP标志,则您的rwlock将阻止上述情况下的读者。

第二种情况是:

  • 最后一个持有者释放锁,并且存在读者和写者等待。

在这种情况下,NPTL始终会优先唤醒写者而不是读者。

综上所述,如果您使用PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP标志,则您的写入程序不应该被饥饿(当然,现在连续的一系列写入程序可能会使读取程序出现饥饿。这就是生活)。您可以通过检查pthread_rwlock_rdlock.cpthread_rwlock_unlock.c中的源代码(非常易读1)来确认所有这些内容。
请注意,还有一个PTHREAD_RWLOCK_PREFER_WRITER_NP,但它似乎没有产生正确的效果 - 很可能是一个错误(或者可能不是 - 请参见jilles的评论)。


1. …至少在我写下这篇答案的2010年是这样的。最新版本的NPTL要复杂得多,我还没有重新进行分析。


1
这里列为UNIX98扩展:http://nptl.bullopensource.org/Tests/Optimization-level-in-nptl.html,但我认为那是一个错误,它实际上是GNU扩展(所有以“_np”结尾的其他函数也是如此)。在实践中,它肯定不会在其他地方可用。我推测“_np”缩写为“NPTL”,意思是“本地POSIX线程库”。我不确定哪个版本的glibc引入了它,但我的盒子上有glibc 2.7。也许可以在glibc邮件列表上询问? - caf
5
嗯,我想我之前的推测是错误的,"_np"很有可能只是指“非可移植”的意思。 - caf
为什么世界上有人会默认使他们的RW锁实现偏向于读者而不是写者,这超出了我的理解范围... - R.. GitHub STOP HELPING ICE
3
我认为原因是PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP选项会在一个线程递归地进行读取锁定时,如果在两次锁定操作之间到达了一个写入者,则会导致死锁。这种死锁被认为比优先考虑读取器更加“严重”,可能是因为POSIX要求递归读锁。如果解决了死锁问题,似乎就没有不同种类的读写锁的必要了。例如,如果有一个等待写入的线程,FreeBSD允许一个读取器进入仅当该线程已经拥有一个以读模式打开的读写锁(它不跟踪所有拥有的读写锁,只跟踪其数量)。 - jilles
1
@R.. “一个线程可以持有多个并发读锁”这一段允许应用程序递归读锁。如果允许,那么在相当正常的情况下死锁是很奇怪的。另一方面,递归写锁可能会死锁或失败。 - jilles
显示剩余3条评论

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