rust : condvar中一对一和多对一模式初探

condvar是不经常碰到的,但其实在tokio之类库中,还是非常核心的作用。
想进一步体会condvar的使用,还是从场景出发。

一、一个通知发送者,一个接收者

假定一个员工收到一个任务,就是模拟是一个时间片,到时了,就会触发通知发出(notify_one)。
通知也有不断发出通知,还是事件触发后再发出通知。这些根据场景需要都可以。
不管形式如何,但mutex中data值的不同状态,wait判断事件是否已经发生的标志。

use std::sync::{ Arc, Condvar, Mutex };
use std::thread;
use std::time::{Duration,Instant};
use std::collections::HashMap;
fn main_single() {let builder = thread::Builder::new();let pair = Arc::new((Mutex::new(false), Condvar::new())); // data为bool值,以此判断事件是否发出let pair2 = Arc::clone(&pair);//单个通知者let handle = builder.spawn(move || {let start = Instant::now();let mut num_send = 0;let mut is_ok =false;while !is_ok {thread::sleep(Duration::from_secs(1));let (lock, cvar) = &*pair2;let mut started = lock.lock().unwrap();num_send +=1;println!("员工:第 {:?} 次报告;任务执行中.....,已耗时: {:?} 秒",num_send, start.elapsed().as_secs());cvar.notify_one();let is_event_happened = start.elapsed().as_secs() >6;if is_event_happened{println!("员工: 报告boss,任务已经完成了!共耗时: {:?} 秒",start.elapsed().as_secs());*started = true;//cvar.notify_all();is_ok = true;}}});let mut is_received = false;let seconds = 1;let start = Instant::now();let mut num_receive = 0;while !is_received {let (lock, cvar) = &*pair;let mut started = lock.lock().unwrap();started = cvar.wait(started).unwrap();if *started == false{println!("boss: 时间过去 {:?} 秒,任务还没完成!",start.elapsed().as_secs());}else {println!("boss: 好!收到员工任务完成信息!现在过去了 {:?} 秒!",start.elapsed().as_secs());is_received = true;}num_receive +=1;println!("boss: 收到! 收到{:?} 次报告,共过去了: {:?} 秒",num_receive, start.elapsed().as_secs());thread::sleep(Duration::from_secs(seconds));}if is_received{println!("任务完成!");}else{println!("任务失败!");}handle.expect("任务失败!boss要崩溃了!").join().unwrap();}
fn main(){main_single()
}

这种场景比较简单,是一对一的。但其它典型的场景可能还有多对一,不断发送通知给一个接收者。象N个员工和一个上级。

二、多个通知者,一个接收者

通过Mutex中包裹一个Hashmap结构,来对多个通知的状态进行管理。
下例构造了3个员工汇报对应一个老板接收的方式。
mutex中值的结构是hashmap<usize,(nums,bool)>结构,分别指的是员工id编号usize,以及此员工通知发送次数nums,以及事件是否发生标志状态bool。
这个数据结构根据自己需要来设定,这里只是一个假设了一个相对信息量复杂的场景。

use std::sync::{ Arc, Condvar, Mutex };
use std::thread;
use std::time::{Duration,Instant};
use std::collections::HashMap;
fn main_multi(){let pair = Arc::new((Mutex::new(HashMap::new()), Condvar::new()));let mut handles  = Vec::new();const PERSONS :usize = 3;//多个成员向1个let each_send_seconds = 1;for i in 0..PERSONS {let _pair = Arc::clone(&pair);let handle = thread::spawn(move || {let start = Instant::now();let mut num_send = 0;let mut is_ok = false;while !is_ok {thread::sleep(Duration::from_secs(each_send_seconds));let (lock, cvar) = &*_pair;let mut locked = lock.lock().unwrap();num_send +=1;let is_event_happened = start.elapsed().as_secs() >= 6;//定义为事件if is_event_happened{println!("员工: 我是员工{:?} ,报告boss,我任务执行完成!共耗时: {:?} 秒",i,start.elapsed().as_secs());(*locked).insert(i,(num_send,true));is_ok = true;}else{println!("员工:我是员工{:?} ,第 {:?} 次报告,任务执行中.....,已耗时:: {:?} 秒",i,num_send, start.elapsed().as_secs());(*locked).insert(i,(num_send,false));}cvar.notify_one();}});handles.push(handle);}let mut is_all_received = false;//let each_recv_seconds = 1;let start = Instant::now();//let mut num_receive = 0;while !is_all_received {let mut is_status = vec![false;PERSONS];//每次轮询全部一次        let (lock, cvar) = &*pair;let mut locked = lock.lock().unwrap();locked = cvar.wait(locked).unwrap();for i in 0..PERSONS{if (*locked).contains_key(&i){let num = (*locked).get(&i).unwrap();let status = num.1;if status{println!("员工:{:?}, 通知次数: {:?} status : {:?}",i,num.0,status);is_status[i] = true;}}}if is_status.iter().all(|&i| i == true){println!("boss: 很好,收到全部员工任务完成的信息!现在过去了 {:?} 秒!",start.elapsed().as_secs());is_all_received = true;}}if is_all_received {println!("任务完成!");}else{println!("任务失败!");}println!("任务总共花了: {:?} 秒", start.elapsed().as_secs());handles.into_iter().for_each(|w| w.join().unwrap());
}fn main(){//main_single();main_multi();
}

运行结果:


员工:我是员工2 ,第 1 次报告,任务执行中.....,已耗时:: 1 秒
员工:我是员工1 ,第 1 次报告,任务执行中.....,已耗时:: 1 秒
员工:我是员工0 ,第 1 次报告,任务执行中.....,已耗时:: 1 秒
员工:我是员工0 ,第 2 次报告,任务执行中.....,已耗时:: 2 秒
员工:我是员工1 ,第 2 次报告,任务执行中.....,已耗时:: 2 秒
员工:我是员工2 ,第 2 次报告,任务执行中.....,已耗时:: 2 秒
员工:我是员工1 ,第 3 次报告,任务执行中.....,已耗时:: 3 秒
员工:我是员工0 ,第 3 次报告,任务执行中.....,已耗时:: 3 秒
员工:我是员工2 ,第 3 次报告,任务执行中.....,已耗时:: 3 秒
员工:我是员工0 ,第 4 次报告,任务执行中.....,已耗时:: 4 秒
员工:我是员工1 ,第 4 次报告,任务执行中.....,已耗时:: 4 秒
员工:我是员工2 ,第 4 次报告,任务执行中.....,已耗时:: 4 秒
员工:我是员工2 ,第 5 次报告,任务执行中.....,已耗时:: 5 秒
员工:我是员工0 ,第 5 次报告,任务执行中.....,已耗时:: 5 秒
员工:我是员工1 ,第 5 次报告,任务执行中.....,已耗时:: 5 秒
员工: 我是员工2 ,报告boss,我任务执行完成!共耗时: 6 秒
员工:2, 通知次数: 6 status : true
员工: 我是员工1 ,报告boss,我任务执行完成!共耗时: 6 秒
员工: 我是员工0 ,报告boss,我任务执行完成!共耗时: 6 秒
员工:0, 通知次数: 6 status : true
员工:1, 通知次数: 6 status : true
员工:2, 通知次数: 6 status : true
boss: 很好,收到全部员工任务完成的信息!现在过去了 6 秒!
任务完成!
任务总共花了: 6 秒

三、多对多模式

在多对一的基础上,还可以衍生中多对多的模式。这个可以扩展一下。也可用到noftify_all。

四、其它相关问题

要注意notify_one()到wait()这个过程,需要特别小心,否则可能会想象中不一样。这个里面有一些操作系统线程 调度机制比较底层,是比较复杂的。

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

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

相关文章

【Qt】设置QT标准对话框为中文字体

设置QT标准对话框为中文字体 一、问题二、解决方法1、找到Qt内置的翻译文件 qt_zh_CN.qm2、在代码中加载该文件 一、问题 在Qt中我们使用的标准对话框都是英文&#xff0c;例如下面的 字体选择对话框&#xff0c;但是实际中我们需要构建的是中文对话框。 所以我们需要使用Qt官…

19篇 vue3进阶

一 基础特性 1. **Composition API**&#xff1a;引入了组合式 API&#xff0c;允许以函数的方式组织组件逻辑。 2. **响应式系统**&#xff1a;使用 Proxy 作为其响应式系统的基础&#xff0c;提供更精确的依赖追踪。 3. **模板语法**&#xff1a;保留了 Vue 2 的模板语法…

MySQL InnoDB事务隔离级别与锁机制深入解析

引言 在当今的数据库系统中&#xff0c;事务管理是确保数据一致性和完整性的关键。事务是数据库操作的基本单元&#xff0c;它将一系列的数据库操作组合成一个逻辑工作单元&#xff0c;要么全部成功执行&#xff0c;要么全部失败回滚&#xff0c;这就是所谓的ACID属性&#xf…

js自动缩放页面,html自动缩放页面,大屏自动缩放页面,数字看板自动缩放页面,大数据看板自动缩放页面

js自动缩放页面&#xff0c;html自动缩放页面&#xff0c;大屏自动缩放页面&#xff0c;数字看板自动缩放页面&#xff0c;大数据看板自动缩放页面 由纯JS实现 html代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"…

vue 注册自定义指令,对输入框输入内容过滤(区分中英文)

注册vue全局指令 对el-input输入框进行最大长度过滤&#xff08;区分中英文&#xff09; 过滤空格 注册全局指令 main.js /*** 输入框最长输入限制* param {*} e 文本内容* param {number} maxlength 最大字符长度* param {boolean} trim 是否过滤空格* returns {string} 最…

acwing算法提高之图论--有向图的强连通分量

目录 1 介绍2 训练 1 介绍 本博客介绍有向图的强连通分量的题目。 连通分量&#xff1a;是针对有向图的一个概念。对于分量中任意两个结点a、b&#xff0c;必然可以从a走到b&#xff0c;且从b走到a。 强连通分量&#xff1a;是针对有向图的一个概念。极大强连通分量&#xff…

【数据结构】单链表的头节点与尾节点

&#x1f388;个人主页&#xff1a;豌豆射手^ &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;数据结构 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进…

玄子Share-计算机网络参考模型

玄子Share-计算机网络参考模型 分层思想 利用七层参考模型&#xff0c;便于在网络通信过程中&#xff0c;快速的分析问题&#xff0c;定位问题并解决问题 将复杂的流程分解为几个功能相对单一的子过程 整个流程更加清晰&#xff0c;复杂问题简单化 更容易发现问题并针对性的…

【Java开发指南 | 第十七篇】Java 方法

读者可订阅专栏&#xff1a;Java开发指南 |【CSDN秋说】 文章目录 简介语法实例构造方法 简介 Java中的方法是用来执行特定任务的一组语句&#xff0c;可以重复使用。它们包含在类或对象中&#xff0c;并通过调用来执行。 举个例子&#xff0c;println() 是一个方法&#xff…

动态内存管理 柔性数组

文章目录 动态内存函数 malloc freecallocrealloc 重新开辟空间realloc 也可以第一个参数为NULL&#xff0c;则是直接开辟内存&#xff0c;类似于malloc用法 常见的动态内存错误对空指针进行解引用操作对开辟的内存越界访问对非动态开辟的内存使用free释放使用free释放动态开辟…

vue2 在循环里,给字体加上随机颜色并加上随机图标且少重复

在循环里&#xff0c;给字体加上随机颜色并加上随机图标且少重复 <template><div class"pbfb5"><el-row :gutter"32"><el-col :xs"6" :sm"6" :lg"6" style"margin-bottom:32px;" v-for&quo…

(四)相关性分析 学习简要笔记 #统计学 #CDA学习打卡

目录 一. 相关性分析简介 二. 相关性分析方法 1&#xff09;连续型变量vs连续型变量&#xff1a;Pearson/Spearman &#xff08;a&#xff09;Pearson &#xff08;b&#xff09;Spearman等级相关系数 2&#xff09;二分类变量&#xff08;自然&#xff09;vs连续型变量&…

macos知名的清理软件 cleanmymac和腾讯柠檬哪个好 cleanmymacx有必要买吗

MacOS是一款优秀的操作系统&#xff0c;但是随着使用时间的增加&#xff0c;它也会产生一些不必要的垃圾文件&#xff0c;占用磁盘空间和内存资源&#xff0c;影响系统的性能和稳定性。为了保持MacOS的清洁和高效&#xff0c;我们需要使用一些专业的清理软件来定期扫描和清除这…

CentOS服务器安装宝塔(图文详解)

宝塔的操作其实就是类似于把linux的指令使用方式&#xff0c;通过宝塔这个第三方工具进行可视化展示&#xff0c;但其实&#xff0c;他还是在操作linux&#xff0c;只是不需要你去记那么多的指令&#xff0c;宝塔把大多数的工具都集成到自己里面&#xff0c;这样你就可以在宝塔…

信号量Semaphore

什么是信号量&#xff1f; C中的信号量&#xff08;Semaphore&#xff09;是一种同步对象&#xff0c;用于控制对共享资源的访问&#xff0c;以防止多个线程或进程同时访问同一资源&#xff0c;从而避免数据不一致的问题。信号量通过维护一个计数值来实现这一功能&#xff0c;…

【Golang】Gin教学-获取请求信息并返回

安装Gin初始化Gin处理所有HTTP请求获取请求的URL和Method获取请求参数根据Content-Type判断请求数据类型处理JSON数据处理表单数据处理文件返回JSON响应启动服务完整代码测试 Gin是一个用Go&#xff08;又称Golang&#xff09;编写的HTTP Web框架&#xff0c;它具有高性能和简洁…

Event loop(Message loop)

事件循环&#xff08;消息循环&#xff09; 浏览器的进程模型 进程 程序运行需要有它自己专属的内存空间&#xff0c;可以把这块内存空间简单的理解为进程 每个应用至少有一个进程&#xff0c;进程之间相互独立&#xff0c;即使要通信&#xff0c;也需要双方同意。 线程 …

Java并发体系--atomic--字段类

atomic--字段类 Atomic字段类是一种原子操作类&#xff0c;用于实现多线程环境下对共享变量的原子操作。它可以确保在并发情况下&#xff0c;对共享变量的操作是原子性的&#xff0c;不会出现线程安全问题。 Atomic字段类提供了一些方法&#xff0c;比如get()和set()方法用…

【Linux学习】Linux权限(二)

文章目录 &#x1f680;Linux权限管理&#x1f680;修改文件的所有者&#x1f680;修改文件或目录的所属组&#x1f680;同时修改为念的拥有者与所属组&#x1f680;文件类型&#x1f680;file指令&#x1f680;目录权限&#x1f680;umask指令&#x1f680;粘滞位 &#x1f68…

Ubuntu22.04.4 - Redis - 笔记

一、安装 sudo apt update sudo apt install redis-serverrootzheng:/etc# redis-cli --version redis-cli 6.0.16二、配置文件修改 配置文件地址 /etc/redis/redis.conf 1、开启远程访问 # 注释掉绑定地址#bind 127.0.0.1&#xff0c;让Redis可远程访问 # bind 127.0.0.1 …