浅谈互斥锁为什么还要和条件变量配合使用

 更新时间:2017年01月12日 08:44:19   投稿:jingxian  
下面小编就为大家带来一篇浅谈互斥锁为什么还要和条件变量配合使用。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

mutex体现的是一种竞争,我离开了,通知你进来。

cond体现的是一种协作,我准备好了,通知你开始吧。

互斥锁一个明显的缺点是它只有两种状态:锁定和非锁定。而条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起配合使用。使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化。一旦其他的某个线程改变了条件变量,他将通知相应的条件变量唤醒一个或多个正被此条件变量阻塞的线程。这些线程将重新锁定互斥锁并重新测试条件是否满足。一般说来,条件变量被用来进行线程间的同步。

两个线程操作同一临界区时,通过互斥锁保护,若A线程已经加锁,B线程再加锁时候会被阻塞,直到A释放锁,B再获得锁运行,进程B必须不停的主动获得锁、检查条件、释放锁、再获得锁、再检查、再释放,一直到满足运行的条件的时候才可以(而此过程中其他线程一直在等待该线程的结束),这种方式是比较消耗系统的资源的。而条件变量同样是阻塞,还需要通知才能唤醒,线程被唤醒后,它将重新检查判断条件是否满足,如果还不满足,该线程就休眠了,应该仍阻塞在这里,等待条件满足后被唤醒,节省了线程不断运行浪费的资源。这个过程一般用while语句实现。当线程B发现被锁定的变量不满足条件时会自动的释放锁并把自身置于等待状态,让出CPU的控制权给其它线程。其它线程 此时就有机会去进行操作,当修改完成后再通知那些由于条件不满足而陷入等待状态的线程。这是一种通知模型的同步方式,大大的节省了CPU的计算资源,减少了线程之间的竞争,而且提高了线程之间的系统工作的效率。这种同步方式就是条件变量。                                       

以上说明可能有点抽象,考虑这样的简单场景:通过伪代码说明。

A线程从队列中取元素,B线程往队列中存放元素。不考虑免锁的实现。需要一个mutex用来保护队列的一致性,避免两个线程同时操作队列破坏数据结构。

当队列为空的时候,A需要不断的探测队列状态 :

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

这就有一个问题,可能在刚进入休眠时,B放入元素了,但仍然需要休眠完整个10s的时间。造成不必要的延迟。当然如果不sleep,也可以,但会造成不必要的CPU开销。使用基于条件变量的事件通知唤醒机制,就可以避免这些问题。

一旦B放入元素完成后就执行pthread_cond_signal(),当前阻塞的线程就会立即被唤醒开始干活儿。

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


条件变量都用互斥锁进行保护,条件变量状态的改变都应该先锁住互斥锁,pthread_cond_wait()需要传入一个已经加锁的互斥锁,该函数把调用线程加入等待条件的调用列表中,然后释放互斥锁,在条件满足从而离开pthread_cond_wait()时,mutex将被重新加锁,这两个函数是原子操作。

可以消除条件发生和线程睡眠等待条件发生间的时间间隙。其他线程在获得互斥量之前不会察觉到这种改变,因为必须锁定互斥量才能计算条件。

总而言之,为了避免因条件判断语句与其后的正文或wait语句之间的间隙而产生的漏判或误判,所以用一个mutex来保证: 对于某个cond的包括(判断,修改)在内的任何有关操作某一时刻只有一个线程在访问。也就是说条件变量本身就是一个竞争资源,这个资源的作用是对其后程序正文的执行权,于是用一个锁来保护。

这样就关闭了条件检查和线程进入休眠状态等待条件改变这两个操作之间的时间通道,这样线程就不会有任何变化。

感觉可以总结为:条件变量用于某个线程需要在某种条件成立时才去保护它将要操作的临界区,这种情况从而避免了线程不断轮询检查该条件是否成立而降低效率的情况,这是实现了效率提高。。。在条件满足时,自动退出阻塞,再加锁进行操作。

以上是关于效率问题,此外互斥锁还有一个缺点就是会造成死锁。

例如线程A和线程B都需要独占使用2个资源,但是他们都分别先占据了一个资源,然后又相互等待另外一个资源的释放,这样就形成了一个死锁。

条件变量起到了阻塞和唤醒线程的作用,所以通常互斥锁要和条件变量配合。

为了解决以上问题,条件变量常和互斥锁一起使用,条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足。使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化。一旦其它的某个线程改变了条件变量,它将通知相应的条件变量唤醒一个或多个正被此条件变量阻塞的线程。这些线程将重新锁定互斥锁并重新测试条件是否满足。

以上就是小编为大家带来的浅谈互斥锁为什么还要和条件变量配合使用全部内容了,希望大家多多支持脚本之家~

相关文章

  • centos7 mariadb主从复制配置搭建详解步骤

    centos7 mariadb主从复制配置搭建详解步骤

    本篇文章主要介绍了centos7 mariadb主从复制配置搭建详解步骤,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2017-02-02
  • 10大HBase常见运维工具整理小结

    10大HBase常见运维工具整理小结

    这篇文章主要介绍了10大HBase常见运维工具整理小结,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2020-07-07
  • Linux实现DHCP服务器的搭建

    Linux实现DHCP服务器的搭建

    Linux常见的服务器有几种,本文详细介绍了Linux实现DHCP服务器的搭建,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • LAMP服务器性能优化技巧之加速PHP

    LAMP服务器性能优化技巧之加速PHP

    目前LAMP (Linux + Apache + MySQL + PHP) 近几年来发展迅速,已经成为Web 服务器的事实标准。本文我们将介绍基于LAMP组合的服务器的性能优化技巧:加速PHP。
    2012-02-02
  • Linux下几种并发服务器的实现模式(详解)

    Linux下几种并发服务器的实现模式(详解)

    下面小编就为大家分享一篇Linux下几种并发服务器的实现模式详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2017-12-12
  • Apache Ant自动化脚本入门教程及常用命令介绍

    Apache Ant自动化脚本入门教程及常用命令介绍

    这篇文章主要介绍了Apache Ant自动化脚本入门教程及常用命令介绍的相关资料,需要的朋友可以参考下
    2016-06-06
  • Linux运维基础系统磁盘管理教程

    Linux运维基础系统磁盘管理教程

    这篇文章主要介绍了Linux运维基础系统磁盘管理教程,附含详细的源码示例,有需要的朋友可以借鉴参考下,希望可以有所帮助,祝大家同学习共进步
    2021-09-09
  • Linux删除文件不同方法效率对比

    Linux删除文件不同方法效率对比

    这篇文章主要介绍了Linux删除文件不同方法效率对比,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08
  • linux网站服务Apache的安装与配置方法详解

    linux网站服务Apache的安装与配置方法详解

    这篇文章介绍下linux网站服务apache的安装与配置方法,本文分为四部分给大家介绍的非常详细,感兴趣的朋友可以参考下
    2016-10-10
  • ubuntu 系统上为php加上redis 扩展的实现方法

    ubuntu 系统上为php加上redis 扩展的实现方法

    这篇文章主要介绍了ubuntu 系统上为php加上redis 扩展的实现方法的相关资料,希望通过本文能帮助到大家,让大家实现这样的功能,需要的朋友可以参考下
    2017-10-10

最新评论