0.序
1.基本概念
2.互斥量的例子
3.互斥量定义
3.1 64位系统
3.2 32位系统
3.3 pthread_mutex_t结构的内容
4.互斥量初始化与销毁
4.1初始化
(1)静态初始化
(2)动态初始化
4.2销毁互斥量
5.小结
0.序
本文涉及到的glibc版本为2.11,若无特别说明,.表示glibc-2.11源代码目录,本文为/usr/src/glibc-2.11。
1.基本概念
临界区:一个存取共享资源的代码段,而这些共享资源无法同时被多个线程访问;即影响共享数据的代码段。
线程同步方法
确保对相同/相关数据的内存访问互斥地进行,即一次只能允许一个线程写数据,其他线程必须等待;
Pthreads使用特殊形式的Edsger Dijkstra信号灯——互斥量;
mutex: mutual(相互),exclusion(排斥);
2.互斥量的例子
下图显示了共享互斥量的三个线程的时序图。
说明
处于标圆形框之上的线段表示相关的线程没有拥有互斥量;
处于圆形框中心线之上的线段表示相关的线程等待互斥量;
处于圆形框中心线之下的线段表示相关的线程拥有互斥量;
过程描述
最初,互斥量没有被加锁;
当线程1试图加锁该互斥量时,因为没有竞争,线程1立即加锁成功,对应线段也移到中心线之下;
然后线程2试图加锁互斥量,由于互斥量已经被加锁,所以线程2被阻塞,对应线段在中心线之上;
接着,线程1解锁互斥量,于是线程2解除阻塞,并对互斥量加锁成功;
然后,线程3试图加锁互斥量,同样被阻塞;
此时,线程1调用函数pthread_mutext_trylock试图加锁互斥量,而立即返回EBUSY;
然后,线程2解锁互斥量,解除线程3的阻塞,线程3加锁成功;
最后,线程3完成工作,解锁互斥量;
3.互斥量定义
3.1 64位系统
file: /usr/include/bits/pthreadtypes.h
该定义来自glibc,其在glibc代码中的位置为./nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h。64位系统在安装glibc的时候会自动拷贝该文件(x86_64版本)到/usr/include/bits目录。
其中,
关于__pthread_list_t(双向链表)和__pthread_slist_t(单向链表)的定义可参考源代码。
3.2 32位系统
file: /usr/include/bits/pthreadtypes.h
该定义来自glibc,其在glibc代码中的位置为./nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h。32位系统在安装glibc的时候会自动拷贝该文件(i386版本)到/usr/include/bits目录。
其中,
3.3 pthread_mutex_t结构的内容
如下是在64位系统的实验结果。
4.互斥量初始化与销毁
4.1初始化
互斥量使用原则:使用前必须初始化,而且只被初始化一次;
(1)静态初始化
使用宏PTHREAD_MUTEX_INITIALIZER声明具有默认属性的静态互斥量;
file: /usr/include/pthread.h
该文件在glibc代码中的位置为./nptl/sysdeps/pthread/pthread.h。
(2)动态初始化
通过pthread_mutex_init()调用动态初始化互斥量;
使用场合
当使用malloc动态分配一个包含互斥量的数据结构时,应使用动态初始化;
若要初始化一个非缺省属性的互斥量,必须使用动态初始化;
也可动态初始化静态声明的互斥量,但必须保证每个互斥量在使用前被初始化,而且只能被初始化一次;
动态初始化代码可参考./nptl/pthread_mutex_init.c文件。其中__pthread_mutex_init()函数即对mutex的各个feild进行初始化。
4.2销毁互斥量
使用pthread_mutex_destroy()释放互斥量。
注意
当确信没有线程在互斥量上阻塞,且互斥量没有被锁住时,可以立即释放;
不需要销毁一个使用PTHREAD_MUTEX_INITIALIZER宏静态初始化的互斥量;
销毁互斥量代码可参考./nptl/pthread_mutex_destroy.c文件。其中__pthread_mutex_destroy()函数设置mutex的相应字段使其不可用。代码如下。
5小结
本文简单介绍互斥量的基本概念,如何初始化和销毁及其注意问题。后文分析其加锁、解锁原理。