情况:
程序正在使用pthread_rwlock_t
,例如foolock
线程,比如T1,获取pthread_rwlock_wrlock()
上的写锁(使用foolock
获得)
T1试图获取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ʂ,NPTL 2.12
编辑1:
很少有澄清:
我不想把读锁升级为写锁
我不想把写锁降级为读锁
我正在研究当已经获得写锁时是否可以授予读锁请求。
简化上下文:
我试图提供两个公共api:(1)
find()
,和(2)update()
find()
使用读锁update()
使用写锁update()
实现要调用find()<我目前的做法是:让每个公共API都有相应的无锁私有版本
公共API执行3个步骤:
(a)取得适当的锁,
(b)调用私有版本,
(c)释放锁
最佳答案
POSIX非常清楚,在pthread_rwlock_rdlock()中:
如果在调用时调用线程持有写锁,则调用线程可能会死锁。
在pthread_rwlock_wrlock()中:
如果在调用时调用线程持有读写锁(无论是读锁还是写锁),则调用线程可能会死锁。
我想这是为了保持简单。
将读锁提升为写锁的功能看起来很有用,但(遗憾的是)不是。考虑一个“索引”数据结构,其中“查找”会自动添加未找到的值:当查找未找到给定值时,提升读锁会很好,并继续将该值添加到索引中,其基础是在同一时间内没有任何变化。不幸的是,这不起作用:考虑两个同时运行的查找,它们都需要写锁:-(因此,强迫程序员放弃读锁并获取写锁至少可以很清楚发生了什么。
请注意,如果“索引查找”在它决定需要写锁的那一点上保持“n”读锁有问题,特别是如果它无法知道“n”是什么的话:-(至少可以通过询问rwlock来发现“n”是很好的!)!
顺便说一下,我发现FreeBSD有:
rw_try_升级(struct rwlock*rw)
尝试将单个共享锁升级为独占锁。当前线程必须持有rw的共享锁。只有当当前线程持有rw上唯一的共享锁,并且它只持有一个共享锁时,此操作才会成功。如果尝试成功,rw_try_upgrade()将返回一个非零值,并且当前线程将持有独占锁。如果尝试失败,rw_try_upgrade()将返回零,并且当前线程仍将持有共享锁。
……但我注意到所有的警告,它什么时候会真正做任何事!
关于将写锁降级为读锁的问题。。。
…如果没有挂起的写锁,则语义非常清楚。然而,如果有一个或多个悬而未决的作家,事情就不那么简单了。
目前,程序员被迫放弃写锁并获取读锁,很清楚发生了什么。
如果“降级”操作被定义为原子的“写-解锁/读-锁”,那么它可以让读卡器在任何挂起的写卡器之前进入,或者只有在没有挂起的写卡器的情况下才能让读卡器进入——第二个让我觉得是更好的选择。“降级”的好处是,在降级之后,人们知道国家没有再次改变——我想这是有用的。
如果在持有写锁时pthread_rwlock_rdlock()
被定义为“降级”,则需要清楚将导致多少级别的锁。如果结果是两个锁,释放第二个锁(读锁)会重新获得第一个锁(写锁)还是保持读锁?[如果可以将读锁“升级”为写锁,如何定义读锁/写锁/升级/降级/解锁的任意序列才能工作?]