设为首页 加入收藏

TOP

MySQL系列:innodb引擎分析之线程并发同步机制(二)
2014-11-23 19:49:18 来源: 作者: 【 】 浏览:89
Tags:MySQL 系列 innodb 引擎 分析 线程 并发 同步 机制
得多。如果在调试状态下,获得锁的同时会向thread_levels的添加一条正在使用锁的信息,以便死锁检查和调试。

3.2 mutex_exit流程图

\

3.4 mutex_t的内存结构关系图

\
3.4mutex获得锁和释放锁的示意图 \

4 rw_lock的实现

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的结构定义:
struct rw_lock_struct
{
 ulint	 reader_count;                         /*获得S-LATCH的读者个数,一旦不为0,表示是S-LATCH锁*/
 ulint	 writer;                                     /*获得X-LATCH的状态,主要有RW_LOCK_EX、RW_LOCK_WAIT_EX、                               
                                                            RW_LOCK_NOT_LOCKED, 处于RW_LOCK_EX表示是一个x-latch
                                                            锁,RW_LOCK_WAIT_EX的状态表示是一个S-LATCH锁*/ 
 os_thread_id_t	 writer_thread;        /*获得X-LATCH的线程ID或者第一个等待成为x-latch的线程ID*/
 ulint	 writer_count;                         /*同一线程中X-latch lock次数*/
 mutex_t	 mutex;                             /*保护rw_lock结构中数据的互斥量*/
 ulint	 pass;                                      /*默认为0,如果是非0,表示线程可以将latch控制权转移给其他线程,
                                                            在insert buffer有相关的调用*/ 
 ulint	 waiters;                                 /*有读或者写在等待获得latch*/
 ibool	 writer_is_wait_ex;

 UT_LIST_NODE_T(rw_lock_t) list;
 UT_LIST_BASE_NODE_T(rw_lock_debug_t) debug_list;

 ulint	 level;                                     /*level标示,用于检测死锁*/

 /*用于调试的信息*/
 char*	 cfile_name;                          /*rw_lock创建时的文件*/
 ulint	 cline;                                     /*rw_lock创建是的文件行位置*/
 char*	 last_s_file_name;                 /*最后获得S-latch时的文件*/
 char*	 last_x_file_name;                 /*最后获得X-latch时的文件*/
 ulint	 last_s_line;                            /*最后获得S-latch时的文件行位置*/
 ulint	 last_x_line;                           /*最后获得X-latch时的文件行位置*/
 ulint	 magic_n;                              /*魔法字*/
};
在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中的自旋函数实现流程是相似的,其目的是要在自旋期间就完成锁的获得。具体细节可以查看sync0rw.c中的rw_lock_s_lock_spin/rw_lock_x_lock_func的代码实现。从上面结构的定义和函数的实现可以知道rw_lock有四种状态:
RW_LOCK_NOT_LOCKED 空闲状态
RW_LOCK_SHARED 处于多线程并发都状态
RW_LOCK_WAIT_EX 等待从S-latch成为X-latch状态
RW_LOCK_EX 处于单线程写状态
以下是这四种状态迁移示意图: \
通过上面的迁徙示意图我们可以很清楚的了解rw_lock的运作机理,除了状态处理以外,rw_lock还为debug提供了接口,我们可以通过内存关系图来了解他们的关系: \

5 死锁检测与调试

innodb除了实现自定义mutex_t和rw_lock_t以外,还对这两个类型的latch做了调试性死锁检测, 这大大简化了innodb的latch调试,latch的状态和信息在可以实时查看到,但这仅仅是在innodb的调试 版本中才能看到。与死锁检测相关的模块主要是mutex level、rw_lock level和sync_cell。latch level相关的定义:
/*sync_thread_t*/
    struct sync_thread_struct
    {
         os_thread_id_t	id;            /*占用latch的thread的id*/
         sync_level_t*	levels;         /*latch的信息,sync_level_t结构内容*/
     };
    
    /*sync_level_t*/
    struct sync_level_struct
    {
         void*	latch;                    /*latch句柄,是mute_t或者rw_lock_t的结构指针*/
         ulint	level;                     /*latch的level标识ID*/
    };
在latch获得的时候,innodb会调用mutex_set_debug_info函数向sync_thread_t中加入一个latch被获得的状态信息,其实就是包括获得latch的线程id、获得latch的文件位置和latch的层标识(具体的细节可以查看mutex_enter_func和mutex_spin_wait)。只有占用了latch才会体现在sync_thread_t中,如果只是在等待获得latch是不会加入到sync_thread_t当中的。innodb可以通过sync_thread_levels_empty_gen函数来输出所有latch等待依赖的cell_t序列,追踪线程等待的位置。

5.1sync_thread_t与sync_level_t的内存结构关系:

\
sync_thread_level_arrays的长度是OS_THREAD_MAX_N(linux下默认是10000),也就是和最大线程个数是一样的。
levels的长度是SYNC_THREAD_N_LEVELS(10000)。

5.2死锁与死锁检测

什么是死锁,通过以下的例子我们可以做个
首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇VirtualBox实现宿主机和虚拟机之.. 下一篇C语言访问MySQL数据库的方法

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: