您的当前位置:首页MySQL系列:innodb源码分析之线程并发同步机制

MySQL系列:innodb源码分析之线程并发同步机制

2020-11-09 来源:飒榕旅游知识分享网

innodb是一个多线程并发的存储引擎,内部的读写都是用多线程来实现的,所以innodb内部实现了一个比较高效的并发同步机制。innodb并没有直接使用系统提供的锁(latch)同步结构,而是对其进行自己的封装和实现优化,但是也兼容系统的锁。我们先看一段innodb内部

innodb是一个多线程并发的存储引擎,内部的读写都是用多线程来实现的,所以innodb内部实现了一个比较高效的并发同步机制。innodb并没有直接使用系统提供的锁(latch)同步结构,而是对其进行自己的封装和实现优化,但是也兼容系统的锁。我们先看一段innodb内部的注释(MySQL-3.23):

Semaphore operations in operating systems are slow: Solaris on a 1993 Sparc takes 3 microseconds (us) for a lock-unlock pair and Windows NT on a 1995 Pentium takes 20 microseconds for a lock-unlock pair. Therefore, we have toimplement our own efficient spin lock mutex. Future operating systems mayprovide efficient spin locks, but we cannot count on that.

大概意思是说1995年的时候,一个Windows NT的 lock-unlock所需要耗费20us,即使是在Solaris 下也需要3us,这也就是他为什么要实现自定义latch的目的,在innodb中作者实现了系统latch的封装、自定义mutex和自定义rw_lock。下面我们来一一做分析。

1 系统的mutex和event

在innodb引擎当中,封装了操作系统提供的基本mutex(互斥量)和event(信号量),在WINDOWS下的实现暂时不做记录,主要还是对支持POSIX系统来做介绍。在POSIX系统的实现是os_fast_mutex_t和os_event_t。os_fast_mutex_t相对简单,其实就是pthread_mutex。定义如下:

typedef pthread_mutex os_fast_mutex_t;
而os_event_t相对复杂,它是通过os_fast_mutex_t和一个pthread_cond_t来实现的,定义如下:

typedef struct os_event_struct
 {
 os_fast_mutex_t os_mutex;
 ibool is_set;
 pthread_cond_t cond_var;
 }os_event_t;
以下是os_event_t的两线程信号控制的例子流程:

对于系统的封装,最主要的就是os_event_t接口的封装,而在os_event_t的封装中,os_event_set、os_event_reset、os_event_wait这三

个方法是最关键的。

2 CPU原子操作

在innodb的mutex(互斥量)的实现中,除了引用系统的os_mutex_t以外,还使用了原子操作来进行封装一个高效的mutex实现。在

系统支持原子操作的情况下,会采用自己封装的mutex来做互斥,如果不支持,就使用os_mutex_t。在gcc 4.1.2之前,编译器是

不提供原子操作的API的,所以在MySQL-.3.23的innodb中自己实现了一个类似__sync_lock_test_and_set的实现,代码是采用

了汇编实现:

 asm volatile("movl $1, %%eax; xchgl (%%ecx), %%eax" :
 "=eax" (res), "=m" (*lw) :
 "ecx" (lw));
这段代码是什么意思呢?其实就是将lw的值设置成1,并且返回设置lw之前的值(res),这个过程都是CPU需要回写内存的,也就是CPU和内存是完全一致的。除了上面设置1以外,还有一个复位的实现,如下:
 asm volatile("movl $0, %%eax; xchgl (%%ecx), %%eax" :
 "=m" (*lw) : "ecx" (lw) : "eax"); 
这两个函数交叉起来使用,就是gcc-4.1.2以后的__sync_lock_test_and_set的基本实现了。在MySQL-5.6的Innodb引擎当中,将以上汇编代码采用了__sync_lock_test_and_set代替,我们可以采用原子操作实现一个简单的mutex.
#define LOCK() while(__sync_lock_test_and_set(&lock, 1)){}
#define UNLOCK() __sync_lock_release(&lock)
显示全文