情况:
pthread_rwlock_t
,例如foolock
pthread_rwlock_wrlock()
上的写锁(使用foolock
获得)pthread_rwlock_rdlock()
foolock
)
foolock
预计会发生什么?
程序(特别是T1)收到错误:
pthread_rwlock_rdlock() returns EDEADLK ("Resource deadlock avoided").
选择此行为的动机是什么?如果授予读锁定会出现什么问题?
解决这种情况的好方法是什么?也许,T1需要保持一些状态,它已经在foolock
上保持写锁定。还有其他建议吗?
我的测试平台是Linux 2.6.32-431.11.2.el6.x86_64,NPTL 2.12
编辑1: 几点澄清:
简化上下文:
find()
和(2)update()
find()
使用了读锁update()
使用写锁定update()
实施想要调用find()<< - 问题 我目前的做法是:
公共API执行3个步骤:
答案 0 :(得分:2)
POSIX非常清楚pthread_rwlock_rdlock():
如果在调用时保持写锁定,则调用线程可能会死锁。
和pthread_rwlock_wrlock():
如果在调用时保持读写锁定(无论是读还是写锁),调用线程可能会死锁。
我怀疑这是为了让事情变得简单。
将读锁定提升到写锁定的能力看起来很有用,但(遗憾的是)它不是。考虑一个“索引”数据结构,其中“查找”自动添加未找到的值:当查找找不到给定值时,提升读锁定并继续将值添加到索引会很好因为在平均时间内没有任何变化。不幸的是,这不起作用:考虑两个同时运行的查找,并且都需要写锁定:-(因此,强制程序员放弃读锁定并获取写锁定至少使得它非常清楚是什么正在发生。
请注意,如果“索引查找”有问题,如果它可以在它确定需要写锁定的时候持有'n'读锁定,特别是如果它无法知道什么是'n'是:-(至少能够通过询问rwlock来发现'n'会很好!
顺便说一下,我发现FreeBSD有:
rw_try_upgrade(struct rwlock * rw)
尝试将单个共享锁升级为独占锁。当前线程必须持有rw的共享锁。只有当前线程在rw上保存唯一的共享锁,并且它只保存一个共享锁时,这才会成功。如果尝试成功,则rw_try_upgrade()将返回非零值,并且当前线程将保持独占锁。如果尝试失败,rw_try_upgrade()将返回零,并且当前线程仍将保持共享锁。
...但我注意到它实际上会做什么的所有警告!
关于将写锁降级为读锁的问题......
...如果没有挂起的写锁,语义非常清楚。但是,如果有一个或多个待处理的编写器,事情就不那么简单了。
目前,程序员被迫放弃写锁并获得读锁,而且非常清楚发生了什么。
如果“降级”操作被定义为原子“写 - 解锁/读锁定”,那么这可以让读者领先于任何未决的作者,或者如果没有未决的作者,只能让读者进入 - - 第二个让我感觉更好。 “降级”的优势在于降级后,人们知道国家没有再次改变 - 我认为这是有用的。
如果持有写锁的pthread_rwlock_rdlock()
被定义为“降级”,则需要清楚会导致多少级别的锁定。如果结果是两个锁定,则会释放second(读锁定)重新获取第一个(写锁定)还是将其保持读锁定状态? [如果可以将读锁定“升级”为写锁定,那么如何定义读锁定/写锁定/升级/降级/解锁的任意序列是否有效?]
答案 1 :(得分:2)
您已经拥有读锁定,因为写锁定允许读取和写入。
所以,你所要求的实质上是一个递归的rwlock,并且不提供一个的原因可能是递归锁更复杂,并且通常表明首先是糟糕的练习。
如果您真的无法重新编写代码,以便知道它所拥有的锁定,那么我同意您在某些特定于线程的结构中跟踪该状态的想法。与C ++中流行的锁定类型相当的东西是合适的。
单独的读写升级案例还有许多其他问题,如gmch所指出的那样。