Cond条件变量

针对场景

应用于一组goroutine等待某一个条件,当条件为true时唤醒某一个或者所有的goroutine

源码解读

type Cond struct {noCopy noCopyL Locker  //当观察(Wait方法)或者修改条件时加锁,Wait方法用锁是保护等待队列的并发安全notify  notifyList   //等待队列checker copyChecker    //运行时检查是否存在复制使用
}// NewCond returns a new Cond with Locker l.
func NewCond(l Locker) *Cond {return &Cond{L: l}
}func (c *Cond) Wait() {c.checker.check()     //检查是否存在复制使用t := runtime_notifyListAdd(&c.notify)   //把调用的goroutine扔到等待队列c.L.Unlock()   //解锁,所以调用Wait前要调用Lock,否则会panicruntime_notifyListWait(&c.notify, t)    //阻塞等待(调用gopark)c.L.Lock()    //加锁,所以最后一次等待被唤醒后要调用一次UnLock解锁
}func (c *Cond) Signal() {c.checker.check()runtime_notifyListNotifyOne(&c.notify)   //唤醒队列头部的goroutine
}func (c *Cond) Broadcast() {c.checker.check()runtime_notifyListNotifyAll(&c.notify)   //唤醒队列所有goroutine
}

使用示例

import ("fmt""sync""time"
)func condUseCase() {/*功能:十个运动员、一个裁判,裁判要等待十个运动员都准备就绪后才能开始比赛*/cond := sync.Cond{L: new(sync.Mutex),}ready := 0for i := 0; i < 10; i++ {i := igo func() {time.Sleep(time.Duration(i) * time.Millisecond)cond.L.Lock()ready++cond.L.Unlock()fmt.Printf("运动员%v号准备就绪\n", i)cond.Signal()}()}cond.L.Lock() //Wait方法会调用UnLock,所以要先Lock一下for ready != 10 {cond.Wait()println("裁判被唤醒")}cond.L.Unlock() //条件满足,最后一次Wait唤醒后会调用Lock,所以要UnLock一下println("所有运动员准备就绪")
}

常见踩坑

调用Wait前未加锁

因为Wait内部把当前goroutine扔到等待队列后会调用Unlock解锁,所以调用Wait前要调用Lock加锁,否则会panic

最后一次Wait返回后未解锁

Wait内部被唤醒后会调用Lock方法拿锁准备保护等待队列,但是最后一次Wait被唤醒后发现条件满足就不会操作等待队列后执行Unlock了,所以要在最后一个Wait返回后调用Unlock解锁

调用Wait后,没有检查条件是否满足就继续执行了

Wait方法返回不代表条件已经满足了,需要检查条件是否满足,如果满足继续执行,否则执行Wait继续等待

总结

使用Cond的场景大部分都可以使用Chan代替
Chan代替用法:创建一个没有buffer的chan,等待的goroutine从chan中获取元素阻塞,往chan中传入元素可以唤醒一个goroutine(Signal)、关闭chan可以唤醒所有goroutine(BroadCast)
使用Chan替代上面的示例:

func chanUseCase() {condChan := make(chan struct{})var mu sync.Mutexready := 0for i := 0; i < 10; i++ {i := igo func() {time.Sleep(time.Duration(i) * time.Millisecond)mu.Lock()ready++mu.Unlock()fmt.Printf("运动员%v号准备就绪\n", i)condChan <- struct{}{}}()}for ready != 10 {<-condChanprintln("裁判被唤醒")}println("所有运动员准备就绪")
}

Cond有三个特性Chan无法满足:

  1. Cond本身具有Locker,不需要创建额外的Locker保证条件的并发修改安全
  2. Cond可以调用多次BroadCast,但是Chan只能调用一次close

Cond:条件变量源码解读相关推荐

  1. PostgreSQL 源码解读(32)- 查询语句#17(查询优化-表达式预处理#2)

    本节简单介绍了PG查询优化表达式预处理中常量的简化过程.表达式预处理主要的函数主要有preprocess_expression和preprocess_qual_conditions(调用preproc ...

  2. 源码解读Mybatis List列表In查询实现的注意事项

    http://www.blogjava.net/xmatthew/archive/2011/08/31/355879.html 在SQL开发过程中,动态构建In集合条件查询是比较常见的用法,在Myba ...

  3. Java Review - Queue和Stack 源码解读

    文章目录 Pre 概述 Queue Deque ArrayDeque 一览 构造函数 属性 方法 addFirst() addLast() pollFirst() pollLast() peekFir ...

  4. Spring5源码 - 05 invokeBeanFactoryPostProcessors 源码解读_2

    文章目录 Pre 源码解读 总体流程 源码分析 细节解析 [初始化对应的集合 & 遍历用户自己手动添加的后置处理器] [调用实现了PriorityOrdered接口的BeanDefinitio ...

  5. Ubuntu 16.04下Caffe-SSD的应用(四)——ssd_pascal.py源码解读

    前言 caffe-ssd所有的训练时的参数,全部由ssd_pascal.py来定义,之后再去调用相关的脚本和函数,所以想要训练自己的数据,首先要明白ssd_pascal.py各个定义参数的大体意思. ...

  6. php yii框架源码,yii 源码解读

    date: 2017-11-21 18:15:18 title: yii 源码解读 本篇博客阅读指南: php & 代码提示: 工欲善其事必先利其器 yii 源码阅读指南: 整体上全貌上进行了 ...

  7. aqs java 简书,Java AQS源码解读

    1.先聊点别的 说实话,关于AQS的设计理念.实现.使用,我有打算写过一篇技术文章,但是在写完初稿后,发现掌握的还是模模糊糊的,模棱两可. 痛定思痛,脚踏实地重新再来一遍.这次以 Java 8源码为基 ...

  8. Linux内核网络协议栈:udp数据包发送(源码解读)

    <监视和调整Linux网络协议栈:接收数据> <监控和调整Linux网络协议栈的图解指南:接收数据> <Linux网络 - 数据包的接收过程> <Linux网 ...

  9. python库源码分析_python第三方库Faker源码解读

    源码背景 Faker是一个Python第三方库,GITHUB开源项目,主要用于创建伪数据创建的数据包含地理信息类.基础信息类.个人账户信息类.网络基础信息类.浏览器信息类.文件信息类.数字类 文本加密 ...

最新文章

  1. ALV输出设置默认布局
  2. Qt Creator设置Qbs
  3. CharNet算法详解
  4. .propertie文件注释
  5. caffe-gpu ubuntu 安装_ubuntu16.04 cuda10.0 配置caffe gpu环境
  6. 别让for循环毁了你的程序(二)
  7. Python小白的数学建模课-B4. 新冠疫情 SIR模型
  8. 风险模型 - 变量筛选
  9. Nacos——Distro一致性协议(架构篇)
  10. 前后端分离-CRUD
  11. 视频教程-VR 游戏创业中的那些坑-其他
  12. laravel跨域问题
  13. APP下载链接点击量如何统计?
  14. R包之tm:文本挖掘包
  15. vue中用ref实现父子组件、孙组件、兄弟组件、非亲子孙组件互相调用的方法
  16. Excel转Json工具(支持GUI模式和命令行模式)
  17. 腾讯将开放多项无障碍AI技术,希望助力更多无障碍场景服务
  18. DataFountain-图书推荐系统
  19. 2019年中国经济四大看点
  20. caffe(ubuntu14.04)学习笔记1——运行MNIST数据集模型

热门文章

  1. bandizip修改压缩文件内容_即将对文件压缩软件Bandizip进行的更改
  2. 【4】 脑部MRI图像肿瘤分类级别
  3. ctfshow_萌新_萌新隐藏题
  4. 经典Java题目:输入一个数字,输出它的大写汉字(阿拉伯数字转汉字)
  5. 大家都在讲敏捷开发模型,但是落地又是迭代模型,迭代模型有哪些优势呢?
  6. TensorFlowX.Y核心基础与AI模型设计开篇
  7. 模式识别与机器学习(PATTERNnbsp;RECO…
  8. HOOK技术四-插件中Activity启动实战
  9. P3669 [USACO17OPEN]Paired Up S 贪心+双指针
  10. 短信验证-1基本的服务器环境搭建