http://www.cnblogs.com/xpchild/p/3782311.html
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) |
下面通过几篇blog分别介绍一下MySQL事务中的表锁,mdl元数据锁,innodb锁:
另外:关于死锁的讨论,这里先列出需要关注的两点:
1. 内存结构的锁,必须控制加锁的顺序,保证逻辑上不出现死锁
2. 事务锁,在无法保证用户的使用数据库行为的时候,需要死锁检测
附tips:
在mutex的使用上的一个小tips:
因为thread如果已经获得了mutex, 那么如果再次lock的话,会产生死锁,要么代码能够控制好,要么可以使用下面的这个结构:
typedef struct my_mutex{ pthread_mutext_t mutex; pthread_t thread; unsigned count; }my_mutex;
在lock之前,使用 mutex_is_owner()来判断是否已经拿到这个mutex了。
bool mutex_is_owner( my_mutex * mutex){ return pthread_equal(thread_self(), mutex->thread);}