互斥锁
特征
在多个线程或者进程间保护一块共享的数据块,保证同一时间只有一个线程或者进程对这块数据进行操作,其实申请操作的进程或者线程被阻塞,等到当前操作完成之后释放mutex,所有等待的进程或者线程竞争这个mutex,只用一个成功,其它的继续阻塞。
数据结构
mutex的数据结构是pthread_mutex_t
mutex属性的数据结构是pthread_mutexattr_t
互斥锁用法
int pthread_mutex_init(const pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
初始化的时候需要指定一个attr值,也可以指定为NULL,初始化的时候使用默认值。
虽然mutex是针对线程开发的,但是它也可以在进程间使用,要使用这个功能就不能再使用默认值了,必须亲自设定attr的值。
互斥锁的属性用法
int pthread_mutexattr_init(const pthread_mutexattr_t * attr);
int pthread_mutexattr_getpshared(pthread_mutexattr_t *restrict attr,int *restrict pshared);
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr,int pshared);
pshared的可选值有两个,一个是PTHREAD_PROCESS_PRIVATE 另一个是PTHREAD_PROCESS_SHARED。PTHREAD_PROCESS_PRIVATE是默认值,这种情况下只能在线程间使用,PTHREAD_PROCESS_SHARED就是进程间需要使用互斥变量保护数据的时候使用,这两个参数的区别直接导致了实现方法的不一样,PTHREAD_PROCESS_PRIVATE的效率要高不少。
int pthread_mutexattr_getrobust(pthread_mutexattr_t *restrict attr,int *restrict robust);
int pthread_mutexattr_setrobust(pthread_mutexattr_t *attr,int robust);
在属性被设置成为PTHREAD_PROCESS_SHARED使用在进程间的时候会有一种线程间不会出现的问题,就是一个持有互斥变量的进程退出了,而且退出的时候没有释放互斥变量,这个时候就要有一个选择,是不管它还是从错误中恢复过来。这两个选择也就是robust的两个取值PTHREAD_MUTEX_STALLED和PTHREAD_MUTEX_ROBUST,stalled是默认值,就是啥也不做。如果设置成robust,等待互斥变量的线程会获取到mutex,并从pthread_mutex_lock返回,但是返回值是EOWNERDEAD,不是正常的返回值0,这种情况下获取到的mutex就要注意啦,在pthread_mutex_unlock之前要执行一个 pthread_mutex_consistent,如果不执行会怎么样呢,就算不执行unlock也会成功就是苦了将到申请互斥锁的线程了,因为他们不能成功的lock,取面代之的是返回一个错误ENOTRECOVERABLE。
int pthread_mutex_consistent(pthread_mutex_t *mutex);
它的意义就是告诉系统这个互斥锁虽然经历了出错的情况,但是它保护的数据状态没有问题,可以继续执行要去。所以在调用pthread_mutex_consistent的时候要进行检查,它要保护的数据到底有没有问题,有没有乱,别不管乱没有乱直接调用pthread_mutex_consistent,那样子程序产生的结果就不可预料了。
int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict attr,int *restrict type);
int pthread_mutexattr_settype(pthread_mutexattr_t *attr,int type);
type 的值决定互斥锁如何互斥,有四个可选值,
PTHREAD_MUTEX_NORMAL
PTHREAD_MUTEX_ERRORCHECK
PTHREAD_MUTEX_RECURSIVE
PTHREAD_MUTEX_DEFAULT
一般default被映射成normal,不进行错误检查,连续锁两次就会死锁了,不拥有锁而执行解锁和已经解锁再次解锁是一个意思,导致的结构就是undefined,这可是出错的节奏。
errorcheck就不一样了,非合法的操作会返回错误,这点比较好啊。recursive是指一个线程可以多次lock,不过你lock多少次要unlock多少次,其它情况表现和errorcheck一样。