博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
条件变量与互斥量
阅读量:7112 次
发布时间:2019-06-28

本文共 2370 字,大约阅读时间需要 7 分钟。

  看了很多文档,就简书说的最好。

  关键词:

    无竞争等待、同步机制(类似ABCABCABC)、条件变量不是锁、线程阻塞、pthread_cond_wait 我理解是一个动作。

     注意点:pthread_cond_broadcast 之后,阻塞队列上的线程都会收到信号,但是cpu能不能取到使用缺不一定,假设取到cpu的线程拿到sig ,发现条件不满足,继续阻塞,等于白跑一圈,此时控制的条件没有改变;而满足条件的线程收到sig,发现我满足条件,不在等待,跑下面可能改变条件的逻辑。条件若改变,又进入下一轮线程唤醒。

  • wait()操作通常伴随着条件检测,如:
    while(pass == 0) pthread_cond_wait(...);
  • signal*()函数通常伴随着条件改变,如:
    pass = 1;pthread_cond_signal(...)
  •  

概念

线程同步的方法有多种,互斥量、信号量、条件变量、读写锁等。互斥量在允许或阻塞对临界区的访问上是很有效的,线程是在对已加锁的互斥量加锁时发生阻塞;条件变量则允许线程由于一些未达到的条件而阻塞,此处的“条件”可以由用户来定义,在访问该条件时需要加锁(互斥量),如果条件没达到,线程将阻塞在该条件上。

条件变量特别适用于多个线程等待某个条件的发生。如果不使用条件变量,那么每个线程就需要不断尝试获得互斥锁并检查条件是否发生,这样大大浪费了系统的资源。

条件变量与互斥量通常一起使用,原因是线程在因条件未满足而阻塞并等待前,需要访问“条件”,而“条件”是允许其它线程修改的,因此,访问“条件”时需要加锁,访问结束后释放锁。所以,这也就可以解释,条件变量的等待操作pthread_cond_wait()需要一个互斥量参数,在pthread_cond_wait()内部将调用线程放到等待队列上后,要解锁互斥量,以让其它线程可以访问“条件”;否则,该线程将一直占用互斥量,其它线程将不能访问“条件”。不过,pthread_cond_wait()内的解锁互斥量只是临时的,在其它线程修改“条件”使其满足要求并唤醒当前阻塞线程时,pthread_cond_wait()内部又会锁住互斥量,这样做的目的是:

  1. 使互斥量的状态在进入、退出pthread_cond_wait()函数时保持一致;
  2. 本身“判断‘条件’是否满足要求,否则阻塞并等待‘条件’”这部分程序属于临界区,在访问临界区前对互斥量加锁,退出临界区后对互斥量解锁是应有的操作,也就是说,真正地释放互斥量锁的操作在退出临界区后;所以,在pthread_cond_wait()函数结束时,应保持互斥量的加锁状态;

通常,“判断‘条件’是否满足要求,否则阻塞并等待‘条件’”这部分临界区代码中的“判断‘条件’”采用while循环来做,因为pthread_cond_wait()在阻塞并等待的过程中,“条件”满足要求后,其它线程会调用pthread_cond_signal()或pthread_cond_broadcast()唤醒阻塞线程,在pthread_cond_wait()将其从阻塞队列放到就绪队列及pthread_cond_wait()重新获取互斥锁之间,其它线程有可能又改变了“条件”,使得此时的“条件”已不再满足要求;因此,若不采用while()循环判断“条件”是否成立,在阻塞线程被唤醒之后,它以为“条件”满足要求,实际上已经被其它线程修改了。

当其它线程修改了“条件”使之满足要求后,会调用pthread_cond_signal()或pthread_cond_broadcast()发送信号,发送信号的步骤顺序有两种:

  • 顺序一
    1. 调用pthread_mutex_lock()对互斥量加锁;
    2. 改变条件使之满足要求;
    3. 向阻塞并等待条件的线程发送信号(比如调用pthread_cond_broadcast());
    4. 调用pthread_mutex_unlock()对互斥量解锁;
  • 顺序二
    1. 调用pthread_mutex_lock()对互斥量加锁;
    2. 改变条件使之满足要求;
    3. 调用pthread_mutex_unlock()对互斥量解锁;
    4. 向阻塞并等待条件的线程发送信号(比如调用pthread_cond_broadcast());

这两种步骤顺序都可以,但都存在一些不足。在顺序一中,发送条件成立信号的步骤在对互斥量解锁之前,也就是发送线程仍是占有锁的,当阻塞线程收到信号后结束休眠,但pthread_cond_wait()在退出之前会对互斥量重新加锁,可发送信号的线程尚未释放锁,所以刚结束休眠的阻塞线程,对互斥量加锁又导致阻塞了;在顺序二中,发送条件成立信号的步骤在对互斥量解锁之后,此时发送信号时,发送线程已经解锁互斥量,但在刚解锁互斥量之后,有可能其它线程在发送线程发送信号之前,成功对互斥量加锁,拿到了“条件”的访问权,因此,可以修改“条件”,这样一来,使得“条件”不再满足阻塞线程的要求,但发送线程不知道,仍会调用pthread_cond_broadcast()发送信号,阻塞线程收到信号后被唤醒,可此时的“条件”是不满足要求的,这一点可以通过while循环判断“条件”是否成立来修正,即便阻塞线程被唤醒,但它仍会判断“条件”是否成立,不成立则继续阻塞等待。

作者:蓝雪冬荷
链接:https://www.jianshu.com/p/3674c7ee5191
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

  https://www.jianshu.com/p/3674c7ee5191

转载于:https://www.cnblogs.com/ashen/p/9625504.html

你可能感兴趣的文章
Android fragment笔记整理
查看>>
velocity的一些优化记录
查看>>
Oracle---使用PL/SQL Developer连接Oracle12C(64位)版本
查看>>
④云上场景:浙江网商银行,三层金融云实践
查看>>
mongoDB VS PostgreSQL dml performance use python (pymongo & py-postgresql)
查看>>
Github上的star和fork是什么
查看>>
说说 ParcelJS
查看>>
2018.03.08、View的事件分发机制笔记
查看>>
基于ubuntu16.04快速构建Hyperledger Fabric网络
查看>>
前端异常处理最佳实践
查看>>
# 基于VirtualApk的Android手游SDK插件化架构(一)
查看>>
jvm类加载机制
查看>>
让更多人知道你——给开源库提交 pr
查看>>
使用ipmi调节r410的风扇转速
查看>>
Spring Cloud超简单十分钟入门实例
查看>>
Linux环境Apache2.4+mysql5.7+php5.6快速安装mysql
查看>>
MySql 日常指导,及大表优化思路
查看>>
设计模式之 - 单例模式
查看>>
用 Python 脚本,监听附近网络 Wi-Fi 设备,通过邮件和微信进行消息推送
查看>>
巅峰之证!首位阿里云ACE认证专家产生
查看>>