线程互斥锁作用:
线程互斥锁通过锁机制来实现线程间的同步。在同一时刻,线程互斥锁只允许一个线程执行一个关键部分的代码。
简单来说,就是当多个线程试图对同一个互斥锁执行加锁操作时,只有一个线程可以获得该锁,并对其进行加锁操作,而其他线程将无法获得该锁,直到加锁线程对互斥锁解锁,其他线程才能获得该锁。
举个例子,如果当前有一个全局变量 number ,需要多个线程对其进行操作,但由于多个线程都可以更改number,可能会造成数据不同步。此时就需要用互斥锁将线程中对全局变量操作的代码 锁住,线程每次对全局变量操作前,必须先访问锁,如果锁处于开放状态,则加锁并操作全局变量,如果锁已被某个线程使用,则说明当前已有线程正在对 number 进行操作,那么此线程进行等待或不继续操作,以此达到全局变量 number 在各个线程中数据同步的目的。
线程互斥锁用法:
1) 操作互斥锁的函数:
pthread_mutex_init () //初始化一个互斥锁
pthread_mutex_destory() //注销一个互斥锁
pthread_mutex_lock() //给指定互斥锁加锁,如果不成功,则线程阻塞等待
pthread_mutex_unlock() //解锁
pthread_mutex_trylock() //测试加锁,如果不成功立即返回,错误码为EBUSY
pthread_mutex_init () //初始化一个互斥锁
pthread_mutex_destory() //注销一个互斥锁
pthread_mutex_lock() //给指定互斥锁加锁,如果不成功,则线程阻塞等待
pthread_mutex_unlock() //解锁
pthread_mutex_trylock() //测试加锁,如果不成功立即返回,错误码为EBUSY
2) 函数用法:
1> 锁的初始化:
使用互斥锁前必须进行初始化操作。初始化方式有两种:一种是静态赋值法,将宏结构常量PTHREAD_MUTEX_INITIALIZER直接赋给互斥锁,操作语句如下:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER ;
对于静态初始化的互斥锁(一般为全局变量),锁的类型为默认类型,即普通锁,不需要再调用 pthread_mutex_init() 函数对其进行初始化。
而动态初始化则需要利用 pthread_mutex_init() 函数,该函数原型如下:
#include<pthread.h>
int pthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr) ;
函数的第一个参数是一个互斥锁 (pthread_mutex_t类型) ,第二个参数 mutexattr 是锁的属性,也即锁的类型,如果为NULL则为默认属性。互斥锁的属性与特点如下:
PTHREAD_MUTEX_TIMED_NP:此为缺省值,即默认属性,也就是普通锁,同一个线程可以对其多次加锁,但只需要解锁一次。当一个线程对其加锁后,其余请求加锁的线程形成等待队列,当加锁线程解锁后,按队列顺序获得锁。
PTHREAD_MUTEX_RECURSIVE_NP:嵌套锁,同一个线程可以对其多次加锁,但解锁时需要同样次数的解锁操作才可以释放锁。调度方式与普通锁相同,有多个线程请求锁时形成等待队列,当该互斥锁解开时,按照等待队列的顺序获得锁。
PTHREAD_MUTEX_ERRORCHECK_NP:检错锁,同一个线程只允许对该锁进行一次加锁操作,即不能重复加锁,如果一个线程请求多次加锁,会返回EDEADLK。调度方式与普通锁相同。
PTHREAD_MUTEX_ADAPTIVE_NP:适应锁,同一个线程允许对该锁重复加锁,解锁时只需要一次解锁操作即可。调度方式为,加锁线程解锁后,所有请求该锁的线程自由竞争。
锁的属性是一个 pthread_mutexattr_t 型结构体:
typedef union
{
char __size[__SIZEOF_PTHREAD_MUTEXATTR_T];
int __align;
} pthread_mutexattr_t;
在使用时,将锁的类型赋给该结构体的 __align成员,然后将结构体变量的地址传入初始化函数的第二个参数即可。
2> 锁的清除:
当一个锁使用完毕后,必须进行清除,释放锁占用的资源。清除锁的函数是 pthread_mutex_destroy() ,函数原型如下:
int pthread_mutex_destroy (pthread_mutex_t *mutex) ;
使用清除函数需要注意的就是,希望清除的锁必须是未加锁状态,如果锁处于锁定状态,调用清除函数会返回EUBSY。函数执行成功时返回0。
清除一个互斥锁意味着释放它所占用的资源,但由于Linux系统中,线程互斥锁并不占用内存,因此 pthread_mutex_destroy() 除了了解互斥锁当前的状态以外,并没有别的操作。
3> 锁的操作:
锁的操作主要包括加锁 pthread_mutex_lock() 、解锁 pthread_mutex_unlock() 和测试加锁 pthread_mutex_trylock()三个。
函数原型如下:
int pthread_mutex_lock (pthread_mutex_t *mutex) ;
int pthread_mutex_trylock (pthread_mutex_t *mutex) ;
int pthread_mutex_unlock (pthread_mutex_t *mutex) ;
pthread_mutex_lock() 函数如果加锁不成功,则会使调用者线程挂起,直到该锁被解开,此函数执行成功,线程继续执行。
pthread_mutex_trylock() 函数如果加锁成功返回0,如果加锁不成功,则返回非零值。
pthread_mutex_unlock() 函数如果解锁成功返回0,如果不成功,则返回非零值。
在同一进程中的线程,如果加锁后没有解锁,则任何其他线程都无法再获得该锁 。
不论哪种类型的锁,都不可能被两个不同的线程同时得到,而必须等待解锁。
对于普通锁和适应锁类型,解锁者可以是同进程内任何线程;
对于检错锁和嵌套锁则必须由加锁者解锁才有效,否则返回EPERM;
以下是验证代码:
/*************************************************************************
> File Name: pthread_test7.c
> Author: zhaobaojin
> BLOG: blog.csdn.net/zhaobaojin1006
> Mail: 1279742553@qq.com
> Created Time: 2015年08月03日 星期一 14时52分48秒
************************************************************************/
#include<stdio.h>
#include<pthread.h>
pthread_mutex_t mutex ;
void thread1(void *arg) ; /*线程函数1*/
void thread2(void *arg) ; /*线程函数2*/
int main(void)
{
int *status1, *status2 ;
pthread_t thid1 ,thid2;
pthread_mutexattr_t mutexattr ;
//mutexattr.__align = PTHREAD_MUTEX_RECURSIVE_NP ; /*将互斥锁初始化为嵌套锁*/
//mutexattr.__align = PTHREAD_MUTEX_ADAPTIVE_NP ; /*将互斥锁初始化为适应锁*/
mutexattr.__align = PTHREAD_MUTEX_ERRORCHECK_NP ; /*将互斥锁初始化为检错锁*/
pthread_mutex_init (&mutex, &mutexattr) ;
//pthread_mutex_init (&mutex, NULL) ; /*将互斥锁初始化为普通锁*/
if(pthread_create(&thid1, NULL, (void *)thread1, NULL) != 0) {
printf ("new thread create failed\n") ;
}
if(pthread_create(&thid2, NULL, (void *)thread2, NULL) != 0) {
printf ("new thread create failed\n") ;
}
pthread_join (thid1, (void *)&status1) ;
pthread_join (thid2, (void *)&status2) ;
pthread_mutex_destroy (&mutex) ;
return 0 ;
}
void thread1(void *arg)
{
pthread_mutex_lock (&mutex) ; /*给嵌套锁加锁*/
sleep (10) ;
pthread_mutex_unlock (&mutex) ;
pthread_exit (0) ;
}
void thread2(void *arg)
{
sleep (2) ; /*等待线程thread1先给嵌套锁加锁*/
if(pthread_mutex_trylock(&mutex) != 0) { /*尝试给互斥锁加锁*/
printf ("i can't get the lock\n") ;
}
if(pthread_mutex_unlock (&mutex) != 0) {
printf ("i can't unlock the lock\n") ;
pthread_exit (0) ;
}
else {
printf ("i can unlock the lock\n") ;
if(pthread_mutex_trylock (&mutex) != 0) {
printf ("i can't get the lock\n") ;
}
else {
printf ("i get the lock\n") ;
}
}
pthread_exit (0) ;
}
利用不同的注释测试不同的锁是否能被其他线程解开。