一.linux中线程间通信同步机制方法1——互斥量(mutex)
1.为啥要有互斥量?
在linux编程享受多线程带来便利的同时,也需要注意多线程在访问一段共享资源的代码片段(术语:临界区),这段代码的执行不应该被其他线程中断,要保证这段代码的执行是原子操作。
其中linux中的互斥量就可以保证多线程对共享资源访问的时的原子操作。当然还有其他的方法,比如:条件变量。本文我们只介绍互斥量(mutex).
二.互斥量的使用方法
2.1.静态分配的互斥量且使用默认属性
初始化直接使用PTHREAD_MUTEX_INITIALIZER.
使用PTHREAD_MUTEX_INITIALIZER初始化的互斥量不需要调用pthread_mutex_destory()进行销毁。
例如:
static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER.
2.2.互斥量上锁和解锁
int pthread_mutex_lock(pthread_mutex_t *mutex)
该函数如果传参的互斥量已经被其他线程持有了锁,那么该函数会一直阻塞,直到该互斥量被解锁。
所以如果调用该函数的线程之前已经将目标互斥量锁定了,那么对于默认互斥量的类型会发生死锁。
int pthread_mutex_unlock(pthread_mutex_t *mutex)
该函数是解锁线程已将互斥量锁定的互斥量。该函数不能对未锁定的互斥量去解锁。
此外还有pthread_mutex_tylock()和pthread_mutex_timedlock()
2.3.互斥量死锁问题场景
一个线程对多个共享资源同时访问,每个资源又被不同的互斥量管理,当超过一个线程加锁同一组互斥量时,就有可能发生死锁。
避免的方法就是:
当多个线程对同一组互斥量访问时,采用相同的顺序进行加锁。
2.4 动态初始化互斥量
上面已经提到PTHREAD_MUTEX_INITIALIZER只能初始化静态分配且携带默认属性的互斥量。但是其他情况下必须使用pthread_mutex_init()
另外使用pthread_mutex_init()初始化的互斥量使用完之后必须要使用pthread_mutex_destory()将其销毁。
2.5互斥量的属性
PTHREAD_MUTEX_NORMAL // 不进行任何错误检查与死锁检查
PTHREAD_MUTEX_ERRORCHECK // 提供错误检查,可以作为软件调试工具,检查程序哪里违反了互斥量的使用规则。
PTHREAD_MUTEX_DEFAULT // 提供默认特性和行为
PTHREAD_MUTEX_RECURSIVE
1.允许同一线程在互斥量解锁之前对互斥量进行多次加锁
2.内部维护了锁的计数,在解锁次数和加锁次数不相同的情况下不会释放锁