linux中互斥量与条件变量的使用

本文介绍Linux下互斥锁与条件变量的基本概念、使用方法及实例代码。阐述如何利用互斥锁确保线程安全地访问共享资源,并通过条件变量实现线程间的同步与等待。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、Linux下的互斥量:

对于某个共享资源,它是被多个线程共同拥有的,不能被某一个线程单独占有,当某个线程使用这个共享资源时其他线程不能使用,这时就需要一个互斥量来控制对共享资源的互斥访问。总而言之互斥量是为了使线程之间能够互斥的访问某个共享资源。

初始化:

互斥量的类型pthread_mutex_t mutex_, 在使用该互斥量前要对其初始化。对互斥量的初始化方法有两种:

1、  使用PTHREAD_MUTEX_INITIALIZER静态分配

         mutex = PTHREAD_MUTEX_INITIALIZER

2、  使用库函数pthread_mutex_init动态分配,然后在使用pthread_mutex_destroy释放。

        int pthread_mutex_init(pthread_mutex_t *mutex_,pthread_mutexattr_t * res);

        int pthread_mutex_destory(pthread_mutex_t * mutex_);

返回值为0,说明函数执行成功;否则,执行失败;


加锁/解锁

         intpthread_mutex_lock(pthread_mutex_t * mutex_);

         intpthread_mutex_unlock(pthread_mutex_t * mutex_);

返回值为0,说明函数执行成功;否则,执行失败;


例子:

对于一个全局变量counter= 0作为共享资源,现在有两个线程thread1和thread2函数对其进行操作。其中,thread1对counter执行加1操作,thread2用于控制当counter>=0时打印出消息并且将其恢复为0。

代码:

intcounter=0;

pthread_mutex_tmutex;

void*thread1(void*)

{

       while(1)

       {

              pthread_mutex_lock(&mutex);

              ++counter;

              pthread_mutex_unlock(&mutex);

       }

}

 

void*thread2(void*)

{

       while(1)

       {

              pthread_mutex_lock(&mutex);

             if(counter>=100000000)

              {

                     cout<<"counter is:"<<counter<<endl;

                     counter=0;

                     pthread_mutex_unlock(&mutex);

              }

              else

              {

                     pthread_mutex_unlock(&mutex);

              }

}

 

intmain()

{

       pthread_mutex_init(&mutex,NULL);

       pthread_tth1,th2;

       pthread_create(&th1,NULL,thread1,NULL);

       pthread_create(&th2,NULL,thread2,NULL);

       pthread_join(th2,NULL);

       pthread_join(th1,NULL);

       pthread_mutex_destroy(&mutex);

       return0;

}

这种情况下,由于线程2中的判断语句很多情况都不满足,但该线程同样被执行,与线程1争夺CPU资源,造成大量CPU大量时间做无用功。

 

二、linux下的条件变量

条件变量为:pthread_cond_t cond;


初始化

在使用该条件变量前要对其初始化。对条件变量的初始化方法有两种:

1、  使用PTHREAD_COND_INITIALIZER静态分配

        cond = PTHREAD_COND_INITIALIZER

2、使用库函数pthread_cond_init动态分配,然后在使用pthread_cond_destroy释放

        int pthread_cond_init(pthread_cond_t *mutex_, pthread_condattr_t* res);

        int pthread_cond_destory(pthread_mutex_t * cond);

返回值为0,说明函数执行成功;否则,执行失败;


等待

函数:pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t * mute);

1、在使用pthread_cond_wait之前要对mutex加锁(pthread_mutex_lock(&mutex))。然后执行wait函数,在wait函数中,首先解锁,然后如果不满足条件,该线程进入阻塞状态,进入阻塞队列。等待cond的信号,直到条件满足后,激活并该阻塞线程,离开wait函数之前会重新锁定mutex。

2、pthread_cond_wait函数内部相当于解锁互斥量,等待条件满足信号,加锁互斥量。在其他线程中当条件满足时会使用pthread_cond_signal(&cond)发送信号激活被该条件变量阻塞的线程。


激活

当条件满足时,使用pthread_cond_signal(&cond)函数发送信号,说明条件满足了从而激活因为等待该条件cond而阻塞的线程,从阻塞队列中出对一个线程执行。当然也可以使用pthread_cond_broadcast(&cond);激活所有因为该条件而阻塞的线程。

 

三、互斥锁与条件变量的使用

简介

线程A中:

if(条件满足时)

{

                  pthread_cond_signal(&cond);//发出信号,说明条件已经满足

}

 

 

线程B中:

pthread_mutex_lock(&mutex);

pthread_cond_wait(&cond, &mutex);//解锁,因为等待条件而阻塞,当收到信号后激活并且加锁

pthread_mutex_unlock(&mutex);


例子代码

int counter=0;

pthread_mutex_t mutex;

pthread_cond_t cond;

void*thread1(void*)

{

       while(1)

       {

              pthread_mutex_lock(&mutex);

              ++counter;

              pthread_mutex_unlock(&mutex);

              if(counter>=100000000)//当条件满足时,发送信号,执行被阻塞的线程

              {

                     pthread_cond_signal(&cond);

              }

       }

}

void*thread2(void*)

{

       while(1)

       {

              pthread_mutex_lock(&mutex);

              while(counter<100000000)

              {

                     pthread_cond_wait(&cond,&mutex);

              }

              cout<<"counter is:"<<counter<<endl;

              counter=0;

              pthread_mutex_unlock(&mutex);

       }

}

 

int main()

{

       pthread_mutex_init(&mutex,NULL);

       pthread_cond_init(&cond,NULL);

       pthread_tth1,th2;

       pthread_create(&th1,NULL,thread1,NULL);

       pthread_create(&th2,NULL,thread2,NULL);

       pthread_join(th2,NULL);

       pthread_join(th1,NULL);

       pthread_mutex_destroy(&mutex);

       pthread_cond_destroy(&cond);

       return0;

}

这样当线程2中条件不满足时,线程2处于阻塞状态,不会与线程1争夺CPU,从而提高CPU效率。


条件变量与互斥锁使用的疑惑点:

(1)关于条件变量的使用为什么要使用while循环,而不是使用if条件判断?

主要是为了避免“虚假唤醒”!

我们知道当使用pthread_cond_wait函数之前要对共享资源加锁,当条件不满足时调用pthread_cond_wait(&cond, &mutex)函数。pthread_cond_wait函数分为三个原子过程:对互斥量解锁,当前线程阻塞,当条件满足时再对互斥量加锁。

问题就出现在:当条件满足时再对互斥量加锁这个过程,因为当条件满足时当前线程不会立即获取互斥量,有可能其他线程在使用互斥量并且对共享资源进行处理,处理后又使得条件不满足。举个例子,假设我们有一个消费者线程,2个生产者线程,他们之间共享一个数据缓冲区buffer。1号生产者获取互斥量往buffer中一个元素后释放互斥量,buffer满了。此时2号生产者也获取互斥量,向往buffer中放数据,但是发现buffer满了,释放互斥量会处于阻塞状态。此时消费者获取互斥量从buffer中取一个数据,buffer中空出一个位置,并发送信号唤醒因为该条件而阻塞的线程。2号线程收到信号,首先它要申请得到互斥量,但是此时互斥量可能被1号线程使用,1号线程发现一个空位,往buffer中填充数据然后释放互斥量,buffer又满了。但是此时2号线程已经被告知buffer有一个空位,并且正准备获取互斥量向buffer中放数据。如果只是简单的用if判断的话,生产者获取互斥量后往一个满的buffer中放数据,这显然是不合理的,造成了“虚假唤醒”。所以在pthread_cond_wait中获取互斥量后要在判断一个次,条件是否满足,以避免“虚假唤醒”。

(2)为什么要调用pthread_join函数?

当某个线程调用pthread_join函数时,当前线程会以阻塞方式停下来,首先执行pthread_join函数里的线程。pthread_join函数里的线程指向完后再继续执行当前线程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值