MySQL的锁:
MySQL内部有很多种类的锁,按照用途不同,可以分为两类:
1. 保护内存结构的锁
server层对于线程共享的变量,基本上使用mutex,rwlock来做保护。
innodb层会增加使用spinlock自旋锁
2. 提供或者保证事务性功能的锁
server提供了MDL锁,表锁两种锁
innodb实现行级锁
原子操作:
在单处理器系统(UniProcessor)结构中,在一个指令周期内完成的都是原子指令,因为硬中断的响应是在每一个cpu指令完成后check的。
而在多处理器结构(Symmetric
Multi-Processor)中,要想完成一个原子指令,还需要保证多个core之间的一致性,这里就引入了锁总线的步骤。
例如:x86体系下的cmpxchg指令
下面使用原子指令来实现mutex,rwlock,spinlock的简单伪代码
1. mutex的伪代码:
mutex_lock:
1
2
3
4
5
6
|
while (1)
if
cmpxchg(*lock,0,1)==0
success
break ;
else
futex(wait)
|
mutex_unlock:
1
2
3
|
if cmpxchg(*lock,1,0)==0
futex(wakeup)
success
|
2. spinlock的伪代码:
spinlock_lock:
1
2
3
4
5
|
while (1)
/* spin */
if
compchg(*lock,0,1)==0
success
break
|
spinlock_unlock:
1
2
|
if cmpxchg(*lock,1,0)==0
success |
3. rwlock的伪代码:
/* variables */
1
2
3
4
|
mutex_lock rw_mutex int r_cnt;
int w_cnt;
int if_has_w_req; /* 防饿死*/
|
rwlock_r_lock:
1
2
3
4
5
6
7
8
9
|
<em>mutex_lock(rw_mutex) while (1)
if (!if_has_w_req && w_cnt ==0)
success
r_cnt++
mutex_unlock(rw_mutex)
return
else
futex(wait)</em>
|
rwlock_r_unlock:
1
2
3
4
|
mutex_lock(rw_mutex) r_cnt--; mutext_unlock(rw_mutex) fetex(wake_up) |
rwlock_w_lock:
1
2
3
4
5
6
7
8
9
10
11
|
mutex_lock(rw_mutex) if_has_w_req++ while (1)
if (r_cnt>0 ||w_cnt >0)
fetux(wait)
else
if_has_w_req--
success
w_cnt++;
break
mutext_unlock(rw_mutex) |
rwlock_w_unlock:
1
2
3
|
mutex_lock(rw_mutex) w_cnt-- mutex_unlock(rw_mutex) |
死锁的讨论
1. 内存结构的锁,必须控制加锁的顺序,保证不出现死锁
2. 事务锁,无法保证用户的行为,需要死锁检测
待续