最近在看InnoDB关于mutex定义部分的代码,由于之前一直工作在MySQL5.6版本里,发现从5.7开始到8.0,这部分代码已经完全进行了重构,本文主要简单记录下新款latch的定义和使用方式。主要记录下涉及的函数和类,不做具体的深入
首先mutex的定义分为三个部分:
PolicyMutex:定义了mutex的接口,包括
enter();
exit();
try_lock();
init();
...
PolicyMutex私有成员m_impl,通过模板实例化为具体的实现方式:
TTASFutexMutex<GenericPolicy> FutexMutex
TTASFutexMutex<BlockMutexPolicy> BlockFutexMutex
TTASMutex<GenericPolicy> SpinMutex
TTASMutex<BlockMutexPolicy> BlockSpinMutex
OSTrackMutex<GenericPolicy> SysMutex
OSTrackMutex<BlockMutexPolicy> BlockSysMutex
TTASEventMutex<GenericPolicy> SyncArrayMutex
TTASEventMutex<BlockMutexPolicy> BlockSyncArrayMutex
可以看到,这里定义了4种Mutex,两种policy,前者是Mutex的具体实现,后者用于跟踪mutex的counter信息
4种mutex包括:
TTASFutexMutex:
- enter: 首先spin通过cas检查锁状态,如果无法通过原子操作获得锁,则调用wait()使用futex进入等待:
syscall(SYS_futex, &m_lock_word, FUTEX_WAIT_PRIVATE, MUTEX_STATE_WAITERS,
0, 0, 0);
//原子检查m_Lock_word是否为MUTEX_STATE_WAITERS, 如果是,则休眠
- exit:释放锁后,如果有等待的线程,同样通过syscall去唤醒
syscall(SYS_futex, &m_lock_word, FUTEX_WAKE_PRIVATE, 1, 0, 0, 0);
futex运行于用户态, 是fast usetablespace mutex的缩写, 对于冲突较小的互斥锁,运行于用户态可以减少内核层切换的开销,futex说明文档
TTASMutex:
- 纯粹的spin loop循环,直到成功加锁(即成功通过原子操作修改lock_word为locked状态)
- 适用于竞争很少的场景
TTASEventMutex
- 传统的Innodb实现方式
- 先spin一段时间,如果一直枷锁失败,则进入condition wait,等待被唤醒
OSTrackMutex:
- 就是封装了pthread_mutex
- 适用于冲突比较剧烈的锁场景
两种Policy