MySQL 同步机制

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012507347/article/details/47254237

MySQL 同步机制

InnoDB没有使用操作系统同步机制,而是自己封装,通过spin(自旋)和wait array(等待队列)的设计提高性能

  • test-and-set(TAS)指令
  • spin lock
  • mutex和自旋
  • rw-lock
  • wait array

test-and-set(TAS)指令

目前的CPU都支持TAS指令。该指令通过读取一个字节或者一个word,然后和0比较,并且无条件的将其在内存中的值设为1,是原子操作。
用到swap-atomic操作,将内存中与寄存器中的值交换。

int test_and_set(volatile int* addr){
    int old_value;
    old_value = swap_atomic(addr,1);  //取值 并 赋1
    if(old_value == 0){
        return 0;
    }
    return 1;
}

spin lock

在TAS的基础上,实现的 一种简单的使用广泛的一种互斥结构。适合于较短的代码(代码过长会导致CPU的等待时间过长,造成CPU的浪费)。

//利用spin lock上锁
void lock(volatile lock_t* lock_status){
    while(test_and_set(lock_status) == 1);
}

若lock_status的值为0,TAS返回0,上锁成功。若lock_status=1,表示对象正在被使用,进入循环,直到对象释放锁。
unlock操作,只需将lock_status置为0即可

mutex和自旋

InnoDB的mutex对象采用test-and-set命令,和spin lock类似。不同之处在于,若TAS返回1,经行自旋操作,一段时间之后若还得不到mutex则进入wait array,等待唤醒。
自旋的目的:

  • 减少对内存的访问
  • 减少上下文的切换
    进入/唤出 wait array 都会产生上下文切换(耗时较长)

部分代码:

void mutex_enter_func(mutex_t* mutex){
    if(!mutex_test_and_set(mutex)){
        get mutex;
        return;
    }
loop:
    //自旋
    while(mutex_get_lock_word(mutex) != 0 && i < SYNC_SPIN_ROUNDS){
        spin;   
        i ++
    }
    if (mutex_test_and_set(mutex) == 0) {
        get mutex;
        return;
    }
    sync_array_reserve_cell(mutex); // reserve a cell from wait array
    mutex_set_waiters(mutex, 1);
    for (i = 0; i < 4; i++) {
        if (mutex_test_and_set(mutex) == 0) {
            get mutex;
            sync_array_free_cell(wait_array,index); //free cell
            return;
        }
    }
    sync_array_wait_event(wait_array,index);
    goto loop;
}

自旋后sync_array_reserve_cell(mutex); 从wait array中分配一个cell,并将mutex->waiters置为1。(waiters表示是否有线程正在等待)然后再循环4次进行TAS操作,检测是否能获得mutex。原因是:

Created with Raphaël 2.1.0 执行的线程 执行的线程 等待的线程 等待的线程 mutex_exit(); reserve cell; (waiters = 0); if(waiters !=0) wake up; (无法唤醒) waiters = 1; wait event;

结果没有线程执行,且waiters = 1 导致无限等待。

rw-lock

在线程共享资源时应设置读/写锁(rw-lock也称latch)

  • s-latch:共享锁,允许共同访问资源。(读)
  • x-latch:排它锁,只允许一个线程访问资源。(写)
\ S X
S 兼容 兼容
X 不兼容 不兼容

x-latch与mutex一样,在得不到latch的时候,先进行自旋,获取不到再进入wait array。
s-latch有所不同,s-latch不支持递归,即一个线程不能执行两个s-latch。自旋的时候要判断,最后加进wait array。

wait array

wait array 由多个cell组成。 每个cell 保存等待唤醒的线程。有一个全局的wait array 对象,sync_primary_wait_array用于对等待latch的线程经行唤醒操作。由sync_array_create初始化,默认建立一个由1000(OS_THREAD_MAX_n)个cell的数组。
由sync_array_reserve_cell();为wait array分配cell,每次分配时扫描整个数组。由sync_array_sigal_object检查队列中是否有线程正在等待,由sync_array_free_cell(); 唤醒线程。


[技术支持]:《MySQL内核InnoDB储存引擎(卷一)》

猜你喜欢

转载自blog.csdn.net/u012507347/article/details/47254237