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

2024-04-23 08:44

本文主要是介绍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()这个过程,需要特别小心,否则可能会想象中不一样。这个里面有一些操作系统线程 调度机制比较底层,是比较复杂的。

这篇关于rust : condvar中一对一和多对一模式初探的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/928318

相关文章

RabbitMQ工作模式中的RPC通信模式详解

《RabbitMQ工作模式中的RPC通信模式详解》在RabbitMQ中,RPC模式通过消息队列实现远程调用功能,这篇文章给大家介绍RabbitMQ工作模式之RPC通信模式,感兴趣的朋友一起看看吧... 目录RPC通信模式概述工作流程代码案例引入依赖常量类编写客户端代码编写服务端代码RPC通信模式概述在R

SQL Server身份验证模式步骤和示例代码

《SQLServer身份验证模式步骤和示例代码》SQLServer是一个广泛使用的关系数据库管理系统,通常使用两种身份验证模式:Windows身份验证和SQLServer身份验证,本文将详细介绍身份... 目录身份验证方式的概念更改身份验证方式的步骤方法一:使用SQL Server Management S

rust 中的 EBNF简介举例

《rust中的EBNF简介举例》:本文主要介绍rust中的EBNF简介举例,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. 什么是 EBNF?2. 核心概念3. EBNF 语法符号详解4. 如何阅读 EBNF 规则5. 示例示例 1:简单的电子邮件地址

Redis高可用-主从复制、哨兵模式与集群模式详解

《Redis高可用-主从复制、哨兵模式与集群模式详解》:本文主要介绍Redis高可用-主从复制、哨兵模式与集群模式的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝... 目录Redis高可用-主从复制、哨兵模式与集群模式概要一、主从复制(Master-Slave Repli

一文带你搞懂Redis Stream的6种消息处理模式

《一文带你搞懂RedisStream的6种消息处理模式》Redis5.0版本引入的Stream数据类型,为Redis生态带来了强大而灵活的消息队列功能,本文将为大家详细介绍RedisStream的6... 目录1. 简单消费模式(Simple Consumption)基本概念核心命令实现示例使用场景优缺点2

Nginx location匹配模式与规则详解

《Nginxlocation匹配模式与规则详解》:本文主要介绍Nginxlocation匹配模式与规则,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、环境二、匹配模式1. 精准模式2. 前缀模式(不继续匹配正则)3. 前缀模式(继续匹配正则)4. 正则模式(大

Linux系统配置NAT网络模式的详细步骤(附图文)

《Linux系统配置NAT网络模式的详细步骤(附图文)》本文详细指导如何在VMware环境下配置NAT网络模式,包括设置主机和虚拟机的IP地址、网关,以及针对Linux和Windows系统的具体步骤,... 目录一、配置NAT网络模式二、设置虚拟机交换机网关2.1 打开虚拟机2.2 管理员授权2.3 设置子

SpringBoot如何通过Map实现策略模式

《SpringBoot如何通过Map实现策略模式》策略模式是一种行为设计模式,它允许在运行时选择算法的行为,在Spring框架中,我们可以利用@Resource注解和Map集合来优雅地实现策略模式,这... 目录前言底层机制解析Spring的集合类型自动装配@Resource注解的行为实现原理使用直接使用M

C#原型模式之如何通过克隆对象来优化创建过程

《C#原型模式之如何通过克隆对象来优化创建过程》原型模式是一种创建型设计模式,通过克隆现有对象来创建新对象,避免重复的创建成本和复杂的初始化过程,它适用于对象创建过程复杂、需要大量相似对象或避免重复初... 目录什么是原型模式?原型模式的工作原理C#中如何实现原型模式?1. 定义原型接口2. 实现原型接口3

大数据spark3.5安装部署之local模式详解

《大数据spark3.5安装部署之local模式详解》本文介绍了如何在本地模式下安装和配置Spark,并展示了如何使用SparkShell进行基本的数据处理操作,同时,还介绍了如何通过Spark-su... 目录下载上传解压配置jdk解压配置环境变量启动查看交互操作命令行提交应用spark,一个数据处理框架