以下是标准库 library/std/src/sys/unix/locks/futex_rwlock.c中的一段代码。 因为使用futex的机制,所以在真正进入等锁阻塞时需要做很多冗余处理。 这里面感觉有一个bug,请大家也帮助看一下,是否真的是bug。
//进入写等待队列的处理
fn write_contended(&self) {
let mut state = self.spin_write();
//假定当前没有线程等待写, 后继处理如果更新,
//则说明有两个以上的线程在竞争获取写锁,所以
//设置state时需要同时更新写等待标志位
let mut other_writers_waiting = 0;
loop {
// 如果unlocked,那试图获取写锁
if is_unlocked(state) {
match self.state.compare_exchange_weak(
state,
state | WRITE_LOCKED | other_writers_waiting,
Acquire,
Relaxed,
) {
//获取成功
Ok(_) => return, // Locked!
Err(s) => {
//获取失败,再次循环
state = s;
continue;
}
}
}
// 不为unlock,进入写等待队列并更新写等待标志
if !has_writers_waiting(state) {
if let Err(s) =
self.state.compare_exchange(state, state | WRITERS_WAITING, Relaxed, Relaxed)
{
//更新失败,说明有同时访问者,需要重新试图获取写锁
state = s;
continue;
}
}
// 不为unlock,且写等待标志位已经设置
// 已经有其他写线程在等待.
other_writers_waiting = WRITERS_WAITING;
// 获取写锁解除的通知变量
let seq = self.writer_notify.load(Acquire);
let s = self.state.load(Relaxed);
下面这段,"is_unlocked(state)"似乎应该是"is_unlocked(s)",前面的代码已经对state做过is_unlocked判断,且中间也没有更新过。
//这个地方似乎错了,本意估计是is_unlocked(s), state此时已经确定
//为lock了
if is_unlocked(state) || !has_writers_waiting(s) {
//这里如果又有变化,那么再次试图获得写锁
state = s;
continue;
}
// 阻塞,等待解锁通知
futex_wait(&self.writer_notify, seq, None);
// 失败或者唤醒,重新再次试图获取写锁
state = self.spin_write();
}
}
1
共 4 条评论, 1 页
评论区
写评论已经在github提交issue并且被确认修改了
这里应该也是一个冗余检查。毕竟前面load和compare_exchange操作中,都使用Relaxed,而不是Release.
建议去IRLO问一句
感觉是 bug。