sem->count 被分为高32位和低32位。高位不为0,用于表示是否有写锁在使用或等待。 低位不为0,用于表示当前是否上锁。所以分为如下情况:
count 值 |
状态 |
备注 |
0x0000000000000000L |
无锁 |
|
0x0000000000000001L |
读者上锁 |
|
0x0000000000000002L |
两个读者上锁 |
因为读锁不互斥 |
0xFFFFFFFF00000001L |
写者上锁 |
|
0xFFFFFFFF00000001L |
写者上锁 |
|
变化时刻 |
count 值 |
备注 |
初始状态 |
0x00000000_00000000L |
|
原子操作 +1 |
0x00000000_00000001L |
|
加锁成功 |
0x00000000_00000001L |
符号位为0就加锁成功 |
解锁后 |
0x00000000_00000000L |
|
变化时刻 |
count 值 |
备注 |
初始状态 |
0x00000000_00000001L |
读者A获取了锁 |
owner 原子操作 +1 |
0x00000000_00000002L |
|
owner 加锁成功 |
0x00000000_00000002L |
读读不互斥 |
读者R 解锁 |
0x00000000_00000001L |
|
owner 解锁 |
0x00000000_00000000L |
|
情况一
变化时刻 |
count 值 |
adjustment 值 |
temp count 值 |
备注 |
初始状态 |
0xFFFF_FFFF_0000_0001L |
0xFFFF_FFFF_FFFF_FFFFL |
|
写者W获取了锁 |
owner 原子操作 +1 |
0xFFFF_FFFF_0000_0002L |
0xFFFF_FFFF_FFFF_FFFFL |
|
符号位不为0,加锁失败 |
owner 获取 wait_lock 后 |
0xFFFF_FFFF_0000_0002L |
0xFFFF_FFFE_FFFF_FFFFL |
|
|
owner 加入等待队列后 |
0xFFFF_FFFE_0000_0001L |
0xFFFF_FFFE_FFFF_FFFFL |
0xFFFF_FFFE_0000_0001L |
owner 进入等待状态 |
写者W 释放锁 |
0xFFFF_FFFF_0000_0000L |
|
0x0000_0000L |
由于 count 为负,且旧值低位-1后为0,继续执行写者W唤醒流程 |
写者W 计算读者数量 |
0xFFFF_FFFF_0000_0000L |
0x0000_0000_0000_0001L |
|
|
写者W 由于最后一个waiter是读者 |
0xFFFF_FFFF_0000_0000L |
0x0000_0001_0000_0001L |
|
|
写者W 唤醒所有读等待者 |
0x0000_0000_0000_0001L |
0x0000_0001_0000_0001L |
|
|
owner 被唤醒 |
0x0000_0000_0000_0001L |
|
|
|
owner 释放锁 |
0x0000_0000_0000_0000L |
|
|
由于 count 为0,释放成功 |
情况二
变化时刻 |
count 值 |
adjustment 值 |
temp count 值 |
备注 |
初始状态 |
0xFFFF_FFFF_0000_0001L |
0xFFFF_FFFF_FFFF_FFFFL |
|
写者W获取了锁 |
owner 原子操作 +1 |
0xFFFF_FFFF_0000_0002L |
0xFFFF_FFFF_FFFF_FFFFL |
|
符号位不为0,加锁失败 |
写者W 释放锁 |
0x0000_0000_0000_0001L |
|
0x0000_0001L |
由于 count 为正,释放锁成功 |
owner 获取 wait_lock 后 |
0x0000_0000_0000_0001L |
0xFFFF_FFFE_FFFF_FFFFL |
|
|
owner 加入等待队列后 |
0xFFFF_FFFF_0000_0000L |
0xFFFF_FFFE_FFFF_FFFFL |
0xFFFF_FFFF_0000_0000L |
temp count == RWSEM_WAITING_BIAS,执行owner唤醒流程 |
owner 计算读者数量 |
0xFFFF_FFFF_0000_0000L |
0x0000_0000_0000_0001L |
|
|
owner 由于最后一个waiter是读者 |
0xFFFF_FFFF_0000_0000L |
0x0000_0001_0000_0001L |
|
|
owner 唤醒所有读等待者 |
0x0000_0000_0000_0001L |
0x0000_0001_0000_0001L |
|
|
owner 也是被唤醒者 |
0x0000_0000_0000_0001L |
|
|
|
owner 释放锁 |
0x0000_0000_0000_0000L |
|
|
由于 count 为0,释放成功 |
情况三
变化时刻 |
count 值 |
adjustment 值 |
temp count 值 |
备注 |
初始状态 |
0xFFFF_FFFF_0000_0001L |
0xFFFF_FFFF_FFFF_FFFFL |
|
写者W获取了锁 |
owner 原子操作 +1 |
0xFFFF_FFFF_0000_0002L |
0xFFFF_FFFF_FFFF_FFFFL |
|
符号位不为0,加锁失败 |
owner 获取 wait_lock 后 |
0xFFFF_FFFF_0000_0002L |
0xFFFF_FFFE_FFFF_FFFFL |
|
|
写者W 释放锁 |
0x0000_0000_0000_0001L |
|
0x0000_0000L |
由于 count 为正,释放锁成功 |
owner 加入等待队列后 |
0xFFFF_FFFF_0000_0000L |
0xFFFF_FFFE_FFFF_FFFFL |
0xFFFF_FFFF_0000_0000L |
temp count == RWSEM_WAITING_BIAS,执行owner唤醒流程 |
owner 计算读者数量 |
0xFFFF_FFFF_0000_0000L |
0x0000_0000_0000_0001L |
|
|
owner 由于最后一个waiter是读者 |
0xFFFF_FFFF_0000_0000L |
0x0000_0001_0000_0001L |
|
|
owner 唤醒所有读等待者 |
0x0000_0000_0000_0001L |
0x0000_0001_0000_0001L |
|
|
owner 也是被唤醒者 |
0x0000_0000_0000_0001L |
|
|
|
owner 释放锁 |
0x0000_0000_0000_0000L |
|
|
由于 count 为0,释放成功 |
情况一
变化时刻 |
count 值 |
adjustment 值 |
temp count 值 |
备注 |
初始状态 |
0xFFFF_FFFF_0000_0001L |
0xFFFF_FFFF_FFFF_FFFFL |
|
写者W获取了锁 |
读者R 原子操作 +1 |
0xFFFF_FFFF_0000_0002L |
0xFFFF_FFFF_FFFF_FFFFL |
|
符号位不为0,加锁失败 |
读者R 获取 wait_lock 后 |
0xFFFF_FFFF_0000_0002L |
0xFFFF_FFFE_FFFF_FFFFL |
|
|
读者R 加入等待队列后 |
0xFFFF_FFFE_0000_0001L |
0xFFFF_FFFE_FFFF_FFFFL |
0xFFFF_FFFE_0000_0001L |
读者R 进入等待状态 |
owner 原子操作 +1 |
0xFFFF_FFFE_0000_0002L |
0xFFFF_FFFF_FFFF_FFFFL |
|
符号位不为0,加锁失败 |
owner 获取 wait_lock 后 |
0xFFFF_FFFE_0000_0002L |
0xFFFF_FFFF_FFFF_FFFFL |
|
|
owner 加入等待队列后 |
0xFFFF_FFFE_0000_0001L |
0xFFFF_FFFF_FFFF_FFFFL |
0xFFFF_FFFE_0000_0001L |
读者R 进入等待状态 |
写者W 释放锁 |
0xFFFF_FFFF_0000_0000L |
|
0x0000_0000L |
由于 count 为负,且旧值低32位-1后为0,继续执行写者W唤醒流程 |
写者W 计算读者数量 |
0xFFFF_FFFF_0000_0000L |
0x0000_0000_0000_00002L |
|
|
写者W 由于最后一个waiter是读者 |
0xFFFF_FFFF_0000_0000L |
0x0000_0001_0000_0002L |
|
|
写者W 唤醒所有读等待者 |
0x0000_0000_0000_0002L |
0x0000_0001_0000_0002L |
|
|
读者R 被唤醒 |
0x0000_0000_0000_0002L |
|
|
|
读者R 释放锁 |
0x0000_0000_0000_0001L |
|
|
|
owner 被唤醒 |
0x0000_0000_0000_0001L |
|
|
|
owner 释放锁 |
0x0000_0000_0000_0000L |
|
|
|
情况二
变化时刻 |
count 值 |
adjustment 值 |
temp count 值 |
备注 |
初始状态 |
0xFFFF_FFFF_0000_0001L |
0xFFFF_FFFF_FFFF_FFFFL |
|
写者W获取了锁 |
读者R 原子操作 +1 |
0xFFFF_FFFF_0000_0002L |
0xFFFF_FFFF_FFFF_FFFFL |
|
符号位不为0,加锁失败 |
owner 原子操作 +1 |
0xFFFF_FFFF_0000_0003L |
0xFFFF_FFFF_FFFF_FFFFL |
|
符号位不为0,加锁失败 |
读者R 获取 wait_lock 后 |
0xFFFF_FFFF_0000_0003L |
0xFFFF_FFFE_FFFF_FFFFL |
|
|
读者R 加入等待队列后 |
0xFFFF_FFFE_0000_0002L |
0xFFFF_FFFE_FFFF_FFFFL |
0xFFFF_FFFE_0000_0002L |
读者R 进入等待状态 |
owner 获取 wait_lock 后 |
0xFFFF_FFFE_0000_0002L |
0xFFFF_FFFF_FFFF_FFFFL |
|
|
owner 加入等待队列后 |
0xFFFF_FFFE_0000_0001L |
0xFFFF_FFFF_FFFF_FFFFL |
0xFFFF_FFFE_0000_0001L |
读者R 进入等待状态 |
写者W 释放锁 |
0xFFFF_FFFF_0000_0000L |
|
0x0000_0000L |
由于 count 为负,且旧值低32位-1后为0,继续执行写者W唤醒流程 |
写者W 计算读者数量 |
0xFFFF_FFFF_0000_0000L |
0x0000_0000_0000_00002L |
|
|
写者W 由于最后一个waiter是读者 |
0xFFFF_FFFF_0000_0000L |
0x0000_0001_0000_0002L |
|
|
写者W 唤醒所有读等待者 |
0x0000_0000_0000_0002L |
0x0000_0001_0000_0002L |
|
|
读者R 被唤醒 |
0x0000_0000_0000_0002L |
|
|
|
读者R 释放锁 |
0x0000_0000_0000_0001L |
|
|
|
owner 被唤醒 |
0x0000_0000_0000_0001L |
|
|
|
owner 释放锁 |
0x0000_0000_0000_0000L |
|
|
|
变化时刻 |
count 值 |
adjustment 值 |
temp count 值 |
备注 |
初始状态 |
0xFFFF_FFFF_0000_0001L |
0x0000_0000_FFFF_FFFFL |
|
写者W1获取了锁 |
W2 原子操作+0xFFFFFFFF_00000001L |
0xFFFF_FFFE_0000_0002L |
0x0000_0000_FFFF_FFFFL |
|
旧值不为0 |
W2 获取 wait_lock 后 |
0xFFFF_FFFE_0000_0002L |
0xFFFF_FFFF_FFFF_FFFFL |
|
等待队列为空 |
W2 加入等待队列后 |
0xFFFF_FFFE_0000_0001L |
0xFFFF_FFFF_FFFF_FFFFL |
0xFFFF_FFFE_0000_0001L |
|
owner 原子操作+1 |
0xFFFF_FFFE_0000_0002L |
0xFFFF_FFFF_FFFF_FFFFL |
|
|
owner 获取 wait_lock 后 |
0xFFFF_FFFE_0000_0002L |
0xFFFF_FFFF_FFFF_FFFFL |
|
|
owner 加入等待队列后 |
0xFFFF_FFFE_0000_0001L |
0xFFFF_FFFE_FFFF_FFFFL |
0xFFFF_FFFE_0000_0001L |
owner 进入等待状态 |
W1 释放锁 |
0xFFFF_FFFF_0000_0000L |
|
0xFFFF_FFFE_0000_0001L |
由于 count 为负, 且旧值低32位-1后为0,继续执行w1的唤醒流程 |
W1 判定旧值 |
0xFFFF_FFFF_0000_0000L |
|
0x0000_0000L |
旧值是0,继续执行 w1 的唤醒流程 |
W1 判定下一个等待者是写者 |
0xFFFF_FFFF_0000_0000L |
0xFFFFFFFF00000001L |
|
|
W1 准备唤醒写者 |
0xFFFF_FFFE_0000_0001L |
0xFFFFFFFF00000001L |
0xFFFF_FFFF_0000_0000L |
temp count 与操作 0xFFFFFFFFL 为0,继续唤醒 |
W1 唤醒写者W2 |
0xFFFF_FFFE_0000_0001L |
|
|
|
W2 被唤醒 |
0xFFFF_FFFE_0000_0001L |
|
|
|
W2 释放锁 |
0xFFFF_FFFF_0000_0000L |
|
0xFFFF_FFFE_0000_0001L |
|
W2 判定旧值 |
0xFFFF_FFFF_0000_0000L |
|
0x0000_0000L |
旧值是0,继续执行 w2 的唤醒流程 |
W2 判定下一个等待者是读者 |
0xFFFF_FFFF_0000_0000L |
|
0xFFFF_FFFF_0000_0000L |
由于old count == 0xFFFFFFFF00000000L,所以继续唤醒 |
W2 计算唤醒读者数量 |
0xFFFF_FFFF_0000_0000L |
0x0000_0000_0000_0001L |
|
|
W2 判断最后一个waiter是读者 |
0xFFFF_FFFF_0000_0000L |
0x0000_0001_0000_0001L |
|
|
W2 唤醒所有等待者 |
0x0000_0000_0000_0001L |
|
|
|
owner 被唤醒 |
0x0000_0000_0000_0001L |
|
|
|
owner 释放锁 |
0x0000_0000_0000_0000L |
|
|
|
变化时刻 |
count 值 |
备注 |
初始状态 |
0x00000000_00000000L |
|
原子操作 +1 |
0xFFFFFFFF_00000001L |
|
加锁成功 |
0xFFFFFFFF_00000001L |
旧值为0就加锁成功 |
解锁后 |
0x00000000_00000000L |
|
变化时刻 |
count 值 |
adjustment 值 |
temp count 值 |
备注 |
初始状态 |
0xFFFF_FFFF_0000_0001L |
|
|
|
owner 加锁 |
0xFFFF_FFFE_0000_0002L |
|
|
|