条件变量的使用(golang)

news/2024/5/3 19:12:47/文章来源:https://blog.csdn.net/liupenglove/article/details/137409999

1、背景      

      最近在学习go的一个开源协程池,在源码中有用到锁、信号量,锁相对来说用的是比较多的,信号量相对用的较少,之前研究学习过c++的std::condition_variable,其实和golang的大同小异,个人感觉c++的略强大一些,其wait有两个重载,第二个语法糖的实现主要是为了防止虚假唤醒。

2、介绍

      条件变量的使用场景是,当满足某个条件时,触发某个动作,类似于排队打饭或者挂号看病,当医生或者打饭员准备好后,就触发看病或者打饭的动作。

条件变量有三个函数:

con.Wait()

该函数会将当前协程放入等待队列并阻塞,直到Signal或Broadcast方法将协程从等待队列中移除并唤醒。

con.Signal()

唤醒等待队列中的一个子协程,先唤醒最先阻塞的子协程,被唤醒之后,子协程继续执行。

con.Broadcast()

Broadcast功能类似Signal,不同的是signal只唤醒一个子协程,而broadcast是唤醒所有阻塞的子协程。

3、使用示例

3.1 signal

我们就以在食堂排队打饭为例子,假如本次排队有10位同学排队,这10位同学分别编号为0-9号(就不具体起名字了),当打饭师傅准备好后,就开始排队打饭,示例代码如下:

package mainimport ("fmt""sync""time"
)func DaFan(x int, num *int, wg *sync.WaitGroup, cond *sync.Cond) {defer wg.Done()// 当有一个lock成功后,其他协程阻塞在这里cond.L.Lock()*num++fmt.Println("学号为:", x, "的同学排到了第:", *num, "位")cond.Wait()fmt.Println("学号为:", x, "的同学打饭了")cond.L.Unlock()
}
func main() {var wg sync.WaitGroupnum := 0var lock sync.Mutexcon := sync.NewCond(&lock)for i := 0; i < 10; i++ {wg.Add(1)go DaFan(i, &num, &wg, con)}// 模拟打饭准备time.Sleep(5 * time.Second)// 循环通知这10位同学打饭for i := 0; i < 10; i++ {con.Signal()// 打饭耗时1秒time.Sleep(1 * time.Second)}wg.Wait()
}

上面代码运行结果如下:

3.2 broadcast

broadcast为广播,好比将军一声令下,所有士兵齐刷刷的冲向敌阵,broadcast的应用场景如下:

将军下令,要求全部将士在10s内修整完成,15s后发起总攻,假如我们有十个兵团,分别为1-10号:

package mainimport ("fmt""math/rand""sync""time"
)func GeneralAttack(x int, num *int, wg *sync.WaitGroup, cond *sync.Cond) {defer wg.Done()// 随机一个10秒内的时间用于修整time.Sleep(time.Second * time.Duration(rand.Intn(10)))fmt.Println("兵团", x+1, "在", time.Now().Format("2006-01-02 15:04:05"), "准备完毕,等待总攻")cond.L.Lock()// 准备完毕,等待教练发令cond.Wait()cond.L.Unlock()fmt.Println("兵团", x+1, "开始发起总攻", time.Now().Format("2006-01-02 15:04:05"))
}
func main() {var wg sync.WaitGroupnum := 0var lock sync.Mutexcon := sync.NewCond(&lock)fmt.Println("将军下令,开始修整:", time.Now().Format("2006-01-02 15:04:05"), ",15s后开始总攻")for i := 0; i < 10; i++ {wg.Add(1)go GeneralAttack(i, &num, &wg, con)}// 等待发起总攻time.Sleep(15 * time.Second)fmt.Println("将军下令,开始总攻:", time.Now().Format("2006-01-02 15:04:05"))// 发起总攻con.Broadcast()wg.Wait()
}

运行记录:

liupeng@liupengdeMacBook-Pro test % go run main.go
将军下令,开始修整: 2024-04-06 21:04:32 ,15s后开始总攻
兵团 2 在 2024-04-06 21:04:32 准备完毕,等待总攻
兵团 1 在 2024-04-06 21:04:32 准备完毕,等待总攻
兵团 4 在 2024-04-06 21:04:33 准备完毕,等待总攻
兵团 9 在 2024-04-06 21:04:33 准备完毕,等待总攻
兵团 6 在 2024-04-06 21:04:37 准备完毕,等待总攻
兵团 3 在 2024-04-06 21:04:38 准备完毕,等待总攻
兵团 8 在 2024-04-06 21:04:39 准备完毕,等待总攻
兵团 10 在 2024-04-06 21:04:39 准备完毕,等待总攻
兵团 5 在 2024-04-06 21:04:40 准备完毕,等待总攻
兵团 7 在 2024-04-06 21:04:41 准备完毕,等待总攻
将军下令,开始总攻: 2024-04-06 21:04:47
兵团 6 开始发起总攻 2024-04-06 21:04:47
兵团 7 开始发起总攻 2024-04-06 21:04:47
兵团 2 开始发起总攻 2024-04-06 21:04:47
兵团 3 开始发起总攻 2024-04-06 21:04:47
兵团 8 开始发起总攻 2024-04-06 21:04:47
兵团 10 开始发起总攻 2024-04-06 21:04:47
兵团 5 开始发起总攻 2024-04-06 21:04:47
兵团 1 开始发起总攻 2024-04-06 21:04:47
兵团 9 开始发起总攻 2024-04-06 21:04:47
兵团 4 开始发起总攻 2024-04-06 21:04:47
liupeng@liupengdeMacBook-Pro test % 

如上运行记录,十个兵团在10s内准备完毕,准备完成后等待将军下令发起总攻,每个兵团就是一个协程,并行开始准备,现实情况也是如此,每个兵团准备时间不同,但都在上级要求的时间内准备完成,之后等待将军下令。

使用 条件变量,在调用 Wait() 方法之前,必须要加锁,否则代码会导致程序 panic。原因是调用 Wait 方法,会先把调用者放入等待队列中,然后释放锁。此时如果在未持有锁时调用释放锁的方法,就会导致程序 panic。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_1045944.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

面试算法-171-翻转二叉树

题目 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1] 解 class Solution {public TreeNode invertTree(TreeNode root) {if (root n…

绿联 安装火狐浏览器(Firefox),支持访问路由器

绿联 安装火狐浏览器&#xff08;Firefox&#xff09;&#xff0c;支持访问路由器 1、镜像 linuxserver/firefox:latest 前置条件&#xff1a;动态公网IP。 已知问题&#xff1a; 直接输入中文时&#xff0c;不能完整输入&#xff0c;也可能输入法无法切换到中文&#xff0c;可…

栈与队列2s总结(不含单调栈)

6.栈与队列 栈与队列理论基础 队列是先进先出&#xff0c;栈是先进后出。 C中stack 是容器么&#xff1f; 我们使用的stack是属于哪个版本的STL&#xff1f; 我们使用的STL中stack是如何实现的&#xff1f; stack 提供迭代器来遍历stack空间么&#xff1f; 栈和队列是STL…

ORCAL SQLPLUS上机6-1

SQL> declare2 v_num number:9;3 begin4 v_num:v_num1;5 dbms_output.put_line(v_num);6 end;7 / --定义记录类型&#xff0c;类似结构体&#xff0c;用select...into --定义记录类型&#xff0c;类似结构体&#xff0c;用select...into SQL> declaretype employe…

test4111

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和…

5分钟了解清楚【osgb】格式的倾斜摄影数据metadata.xml有几种规范

数据格式同样都是osgb&#xff0c;不同软件生产的&#xff0c;建模是参数不一样&#xff0c;还是有很大区别的。尤其在应用阶段。 本文从建模软件、数据组织结构、metadata.xml&#xff08;投影信息&#xff09;、应用几个方面进行了经验性总结。不论您是初步开始建模&#xf…

【QT+QGIS跨平台编译】175:【QGIS_App跨平台编译】—【错误处理:未定义的class APP_EXPORT】

点击查看专栏目录 文章目录 一、未定义的class APP_EXPORT二、错误处理 一、未定义的class APP_EXPORT 报错信息&#xff1a; 二、错误处理 第18行增加&#xff1a; #include "qgis_app.h"

文章解读与仿真程序复现思路——电力系统自动化EI\CSCD\北大核心《新型电力系统多阶段输-储协同分布鲁棒规划》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

Adobe After Effects 2024 v24.3 macOS 视频合成及特效制作软件 兼容 M1/M2/M3

Adobe After Effects 是一款适用于视频合成及特效制作软件,是制作动态影像设计不可或缺的辅助工具,是视频后期合成处理的专业非线性编辑软件。 macOS 12.0及以上版本可用 应用介绍 Adobe After Effects简称 AE 是一款适用于视频合成及特效制作软件,是制作动态影像设计不可或缺…

计算分数和-第12届蓝桥杯选拔赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第48讲。 计算分数和&#…

STM32 H7系列学习笔记

必备的API知识 第 1 步&#xff1a;系统上电复位&#xff0c;进入启动文件 startup_stm32h743xx.s&#xff0c;在这个文件里面执行复位中断服务程序。 在复位中断服务程序里面执行函数 SystemInit&#xff0c;在system_stm32h7xx.c 里面。*之后是调用编译器封装好的函数&…

Kubesphere 在 devops 部署项目的时候下载 maven 依赖卡住

Kubesphere 在 devops 部署项目的时候下载 maven 依赖卡住 我下载 下面这段 maven 依赖一直卡住&#xff1a; <build><plugins><plugin><groupId>org.jacoco</groupId><artifactId>jacoco-maven-plugin</artifactId><version>…

LeetCode 80—— 删除有序数组中的重复项 II

阅读目录 1. 题目2. 解题思路3. 代码实现 1. 题目 2. 解题思路 让 index指向删除重复元素后数组的新长度&#xff1b;让 st_idx 指向重复元素的起始位置&#xff0c;而 i 指向重复元素的结束位置&#xff0c;duplicate_num代表重复元素的个数&#xff1b;一段重复元素结束后&am…

Java Web-分层解耦

三层架构 当我们所有代码都写在一起时&#xff0c;代码的复用性差&#xff0c;并且难以维护。就像我们要修改一下服务端获取数据的方式&#xff0c;从文本文档获取改为到数据库中获取&#xff0c;就难以修改&#xff0c;而使用三层架构能很好的解决这个问题。 controller: 控…

PHP 中的 $2y$10,PHP 字符串加密函数 password_hash

PHP 用户密码加密函数 password_hash 自PHP5.5.0之后&#xff0c;新增加了密码散列算法函数(password_hash)&#xff0c;password_hash() 使用足够强度的单向散列算法创建密码的散列 Hash。 password_hash() 兼容 crypt()。 所以&#xff0c; crypt() 创建的密码散列也可用于 …

flask 访问404

当你的项目有自己的蓝图&#xff0c;有添加自己的前缀&#xff0c;也注册了蓝图。 在访问的路由那里也使用了自己的蓝图&#xff0c;如下图 然后你访问的地址也没问题&#xff0c;但是不管怎么样访问就是返回404&#xff0c;这个时候不要怀疑你上面的哪里配置错误&#xff0c;…

【网站项目】校园二手交易平台小程序

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

外包干了25天,技术倒退明显

先说情况&#xff0c;大专毕业&#xff0c;18年通过校招进入湖南某软件公司&#xff0c;干了接近6年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落&#xff01; 而我已经在一个企业干了四年的功能…

【mT5多语言翻译】之五——训练:中央日志、训练可视化、PEFT微调

请参考本系列目录&#xff1a;【mT5多语言翻译】之一——实战项目总览 [1] 模型训练与验证 在上一篇实战博客中&#xff0c;我们讲解了访问数据集中每个batch数据的方法。接下来我们介绍如何训练mT5模型进行多语言翻译微调。 首先加载模型&#xff0c;并把模型设置为训练状态&a…

网络安全指南:安全访问 Facebook 的技巧

在当今数字化时代&#xff0c;网络安全问题越来越受到人们的关注。尤其是在社交媒体平台上&#xff0c;如 Facebook 这样的巨头&#xff0c;用户的个人信息和隐私更容易受到威胁。为了保护自己的在线安全&#xff0c;我们需要采取一些措施来确保在使用 Facebook 时能够安全可靠…