Linux学习笔记:线程互斥锁

线程互斥锁作用:

线程互斥锁通过锁机制来实现线程间的同步。在同一时刻,线程互斥锁只允许一个线程执行一个关键部分的代码。

简单来说,就是当多个线程试图对同一个互斥锁执行加锁操作时,只有一个线程可以获得该锁,并对其进行加锁操作,而其他线程将无法获得该锁,直到加锁线程对互斥锁解锁,其他线程才能获得该锁。

举个例子,如果当前有一个全局变量 number ,需要多个线程对其进行操作,但由于多个线程都可以更改number,可能会造成数据不同步。此时就需要用互斥锁将线程中对全局变量操作的代码 锁住,线程每次对全局变量操作前,必须先访问锁,如果锁处于开放状态,则加锁并操作全局变量,如果锁已被某个线程使用,则说明当前已有线程正在对 number 进行操作,那么此线程进行等待或不继续操作,以此达到全局变量 number 在各个线程中数据同步的目的。

线程互斥锁用法:

1) 操作互斥锁的函数:

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) ;
}

利用不同的注释测试不同的锁是否能被其他线程解开。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值