读锁非互斥
非互斥的意思就是,一个客户端或者线程加锁之后,另一个客户端线程也可以来进行加锁。
还是拿着ReadLock的lua脚本来看看
刚才我们已经分析过第一个线程来加读锁的逻辑了
所以上半截不用重复说了,
hset anyLock mode read
hset anyLock UUID_01:threadId_01 1
set {anyLock}:UUID_01:threadId_01:rwlock_timeout:1 1
pexpire {anyLock}:UUID_01:threadId_01:rwlock_timeout:1 30000
pexpire anyLock 30000
当前的数据结构是这样的
cpp
anyLock: {
"mode": "read",
"UUID_01:threadId_01": 1
}
此时另一个客户端B也要来加读锁,我们来看一下这时候的参数
KEYS[1] = anyLock
KEYS[2] = {anyLock}:UUID_02:threadId_02:rwlock_timeout
ARGV[1] = 30000毫秒
ARGV[2] = UUID_02:threadId_02
ARGV[3] = UUID_02:threadId_02:read
判断mode这个值是不是等于read,在开头的时候这个值就取出来了,这个锁是不是读锁,是的话可以直接进入下面的逻辑。
并且,判断一下,如果当前是写锁的话,但是写锁是自己当前这个线程,是可以进去加读锁的,如果写锁不是自己加的,就不能加读锁了
这就是读锁与读锁的非互斥、读锁与写锁的互斥。
if (mode == 'read') or (mode == 'write' and redis.call('hexists', KEYS[1], ARGV[3]) == 1) then
那再往下的逻辑中,就是往读锁结构中添加键值对
hincrby anyLock UUID_02:threadId_02 1
set {anyLock}:UUID_02:threadId_02:rwlock_timeout:1 1
pexpire anyLock 30000
pexpire {anyLock}:UUID_02:threadId_02:rwlock_timeout:1 30000
添加完后长这样
cpp
anyLock: {
"mode": "read",
"UUID_01:threadId_01": 1,
"UUID_02:threadId_02": 1
}
读锁与写锁互斥
先加读锁后加写锁
上面的lua脚本有判断
if (mode == 'read') or (mode == 'write' and redis.call('hexists', KEYS[1], ARGV[3]) == 1) then
如果当前锁是read ,而要加的锁是 write的话,直接返回进入线程等待。
先加写锁后加读锁的话,要看写锁的加锁逻辑
这里mode对应的值如果不是write的话,直接返回,加锁线程进入等待。
写锁和写锁的互斥
还是上面的lua脚本,如果说当前的数据中mode对应值是write的话,
要判断里面的线程是否是自己当前线程,如果是的话,就可以进去,如果不是的话,就不能加锁
如果这时候进去了, 那就是当前线程加锁的可重入 逻辑