ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、视频、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] ### 读写锁(S-latch|X-latch) innodb为了提高读的性能,自定义了read write lock,也就是读写锁。其设计原则是:     1、同一时刻允许多个线程同时读取内存中的变量     2、同一时刻只允许一个线程更改内存中的变量     3、同一时刻当有线程在读取变量时不允许任何线程写存在     4、同一时刻当有线程在更改变量时不允许任何线程读,也不允许出自己以外的线程写(线程内可以递归占有锁)。     5、当有rw\_lock处于线程读模式下是有线程写等待,这时候如果再有其他线程读请求锁的时,这个读请求将处于等待前面写完成。 从上面5点我们可以看出,rw\_lock在被占用是会处于读状态和写状态,我们称之为S-latch(读共享)和X-latch(写独占),《MySQL技术内幕:innodb引擎》对S-latch和X\_latch的描述如下: | | S-latch | X-latch | | --- | --- | --- | | S-latch | 兼容 | 不兼容 | | X-latch | 兼容 | 不兼容 | innodb中的rw\_lock是在建立在自定义mutex\_t之上的,所有的控制是基于mutex和thread\_cell的。 在rw\_lock\_t获得锁和释放锁的主要接口是:rw\_lock\_s\_lock\_func、rw\_lock\_x\_lock\_func、rw\_lock\_s\_unlock\_func、rw\_lock\_x\_unlock\_func四个关键函数。 其中rw\_lock\_s\_lock\_func和rw\_lock\_x\_lock\_func中定义了自旋函数,这两个自旋函数的流程和mutex\_t中的自旋函数实现流程是相似的,其目的是要在自旋期间就完成锁的获得。 ### 自旋锁 自旋锁的机制就是在短时间内循环获取锁,避免进程从用户态切换到内核态,因为上下文切换影响性能。超过一定时间后,进程仍然切换到阻塞状态,避免大量进程一直循环消耗CPU。 ### 死锁与死锁检测 什么是死锁,通过以下的例子我们可以做个简单的描述:     线程A                                         线程B     mutex1    enter                mutex2        enter     mutex2    enter                mutex1        enter     执行任务                          执行任务     mutex2    release            mutex1          release     mutex1    release            mutex2          release    上面两个线程同时运行的时候,可能产生死锁的情况,就是A线程获得了mutex1正在等待mutex2的锁,同时线程2获得了mutex2正在等待mutex1的锁。在这种情况下,线程1在等线程2,线程2在等线程就造成了死锁。   了解了死锁的概念后,我们就可以开始分析innodb中关于死锁检测的流程细节,innodb的检车死锁的实质就是判断 要进行锁的latch是否会产生所有线程的闭环,这个是通过sync\_array\_cell\_t的内容来判断的。在开始等待cell信号的时候, 会判断将自己的状态信息放入sync\_array\_cell\_t当中,在进入os event wait之前会调用sync\_array\_detect\_deadlock来判 断是否死锁,如果死锁,会触发一个异常。死锁检测的关键在与sync\_array\_detect\_deadlock函数。 以下是检测死锁的流程描述:     1、将进入等待的latch对应的cell作为参数传入到sync\_array\_detect\_deadlock当中,其中start的参数和依赖的cell参  数填写的都是这个cell自己。     2、进入sync\_array\_detect\_deadlock先判断依赖的cell是否正在等待latch,如果没有,表示没有死锁,直接返回. 如果有,先判断等待的锁被哪个线程占用,并获得占用线程的id,通过占用线程的id和全局的sync\_array\_t  等待cell数组状 态信息调用sync\_array\_deadlock\_step来判断等待线程的锁依赖。     3、进入sync\_array\_deadlock\_step先找到占用线程的对应cell,如果cell和最初的需要event wait的cell是同一 个cell,表示是一个闭环,将产生死锁。如果没有,继续将查询到的cell作为参数递归调用 sync\_array\_detect\_deadlock执行第2步。这是个两函数交叉递归判断的过程。 在检测死锁过程latch句柄、thread id、cell句柄三者之间环环相扣和递归,通过latch的本身的状态来判断闭环死锁。在上面的第2步会根据latch是mutex和rw\_lock的区别做区分判断,这是由于mutex和rw\_lock的运作机制不同造成的。因为关系数据库的latch使用非常频繁和复杂,检查死锁对于锁的调试是非常有效的,尤其是配合thread\_levels状态信息输出来做调试,对死锁排查是非常有意义的。 死锁示意图: ![](https://img-blog.csdn.net/20141116105330343?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveXVhbnJ4ZHU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)