互斥锁并不难,只要了解它的函数就可以去简单使用了。
1.初始化锁
1.1动态初始化
对于每把互斥锁,都有一个互斥变量,它是一个特殊的数据类型pthread_mutex_t。
int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutex_attr_t *mutexattr);
我们可以自己建立一个pthread_mutex_t类型变量,再用如上函数初始化,第一个参数就不用说了,传入互斥变量的地址。
第二个变量用于指定锁的属性,一共有四种属性:
1.PTHREAD_MUTEX_TIMED_NP
这是缺省值,第二个参数填NULL还是PTHREAD_MUTEX_TIMED_NP都是一样的。当一个线程加锁后,其他请求这个锁的线程会进入一个队列对待,锁释放后按队列优先级获得锁。具有公平性。
2.PTHREAD_MUTEX_RECURSIVE_NP
嵌套锁,允许同一个线程多次获得同一个锁,并多次解锁。
3.PTHREAD_MUTEX_ERRORCHECK_NP
检错锁,如果同一个线程请求同一个锁,返回EDEADLK;否则和PTHREAD_MUTEX_TIMED_NP操作一样(进入等待队列)
4.PTHREAD_MUTEX_ADAPTIVE_NP
适应锁,如果被锁上了,等解锁后重新竞争,不存在等待队列,而是解锁后先到先得。
1.2静态初始化
pthread_mutex_t其实是一种结构,而PTHREAD_MUTEX_INITIALIZER是一个结构常量。
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
直接这样初始化也是可以的。
2.加锁
2.1阻塞加锁
int pthread_mutex_lock(pthread_mutex_t *mutex);
锁空闲,立即加锁;否则阻塞等待直至解锁
2.2非阻塞加锁
int pthread_mutex_trylock( pthread_mutex_t *mutex);
锁空闲,立即加锁;否则立即返回 EBUSY而非等待
比如主线程需要一个子线程来完成某件事,而子线程加锁在忙,就立即返回,找另一个子线程来完成。
2.3避免死锁的加锁
int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, const struct timesec *restrict tsptr);
可以设置一个阻塞等待时间,如果等待超时了,锁还未释放,则返回ETIMEDOUT,避免两个或多个线程加了锁,又彼此等待锁的释放而产生死锁。
3.解锁
加完锁以后就需要解锁了。使用如下函数即可解锁。
int pthread_mutex_unlock(pthread_mutex *mutex);
4.销毁锁
互斥锁也是资源之一,使用完毕后需要销毁,释放资源,调用如下函数即可完成销毁。
int pthread_mutex_destroy(pthread_mutex *mutex);