互斥量与条件变量

互斥量和条件变量是多线程编程中的关键同步机制。互斥量确保资源在同一时刻只被一个线程访问,防止数据竞争。而条件变量允许线程在资源不可用时阻塞,当资源变得可用时被唤醒,减少了不必要的CPU占用。在C++11中,条件变量通过condition_variable类实现,结合unique_lock进行线程同步,提高效率。
摘要由CSDN通过智能技术生成

我想在这里先说一个跟题目无关的东西,一种学习方法,叫费曼学习法。简单的说,费曼学习法有四个步骤,学习知识要把它教给小孩子、回顾、将语言条理化、传授。

初步理解

在这里我想先用自己的话来描述互斥量和条件变量这两个概念和他们之间的关系。计算机中的一些资源可以被不同的线程共享,但是他们在某个时刻只能被一个线程使用,为了防止某个线程正在使用该资源时被别的线程使用导致线程运行出现错误,我们需要用“锁”这一概念,把共享的资源在使用前锁上,使得该资源只会被它正在使用的线程访问,并在使用后进行解锁。这就是互斥量的概念。互斥量可以简单理解为一种锁,正如其名,它保证了资源的单一访问。

但这样也会带来一个问题就是,在该资源被上锁的时候,其他线程也希望访问该资源,但是因为得不到,就只能一直重复上锁、检查、释放锁、再上锁再检查再释放锁的操作,并且这个过程线程一直在占用CPU的控制权,一直到前一个进程释放了在这个资源上的锁它才能获得资源进行运行。这样做将会造成其他线程一直在等待该线程结束,且非常消耗系统资源的后果。能不能有一种办法,不需要线程自己不停的尝试,而是当资源上的锁被释放时就通知等待该资源的线程,当有线程正在使用资源时就将其他想访问该资源的线程阻塞呢?我们引入了条件变量这个概念。当线程发现资源被锁定时条件变量就会将其阻塞,让出CPU的控制权给其他线程,当资源被释放时,那些阻塞线程被唤醒,线程重新检查资源可用性,从而获得资源并上锁或是重新阻塞。因此条件变量是一种通知模型的同步方式。

条件变量

上边自己的理解说完了,我们还是看一看更严谨的介绍:

条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立"(给出条件成立信号)。为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。

简单场景:

A线程从队列中取元素,B线程往队列中存放元素。需要一个mutex(互斥量)用来保护队列的一致性,避免两个线程同时操作队列破坏数据结构。
当队列为空的时候,A需要不断的探测队列状态 :

while(1)
{ 
if(队列为空)
休眠10s
else
    {
        加锁
        取元素
        解锁
     }
}

这就有一个问题,可能在刚进入休眠时,B放入元素了,但仍然需要休眠完整个10s的时间。造成不必要的延迟。而如果不sleep,A就会一直循环检测是否可用,造成不必要的CPU开销。

使用基于条件变量的事件通知唤醒机制,就可以避免这些问题。
一旦B放入元素完成后就执行pthread_cond_signal(),当前阻塞的线程就会立即被唤醒开始干活儿。

while(1) {
    pthread_mutex_lock();
    pthread_cond_wait();
    取元素;
    pthread_mutex_unlock();
}

condition_variable类

在C++11中,条件变量通过condition_variable类来实现。
条件变量实际上是condition_variable类的对象,通过这个对象可以实现对调用线程的阻塞。条件变量往往需要绑定一个unique_lock(也是互斥锁的一种实现),当在线程中通过条件变量调用wait函数时,该线程就会被阻塞住,直到在另一个线程中调用notify函数来唤醒这个线程。
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

①wait函数会先对传入的unique_lock进行unlock,并且block(阻塞)当前线程,unlock和block的操作,是一个原子行为。然后将当前线程添加到当前condition_variable对象的等待线程列表中;
②当唤醒线程调用notify_all或者notify_one时,就会解除wait线程的阻塞。解除阻塞之后,就会重新对unique_lock进行lock,然后wait函数返回;
③如果wait函数还传入了第二个参数pred,pred参数应当是个bool型的可调用对象。此时调用wait,会先判断第二个参数的返回值,如果返回false,就会执行第①步,否则直接返回;当被唤醒后再次判断第二个参数的返回值,如果返回false,会再次进入阻塞,否则直接返回;
④由于unique_lock的存在,保护了对可调用对象pred的访问。
⑤如果调用notify_all或者notify_one,实际上就是唤醒当前condition_variable对象的等待线程列表中的线程。

参考链接:
费曼学习法
C ++ 多线程:条件变量、unique_lock
浅谈互斥锁为什么还要和条件变量配合使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值