rust学习(简单handler实现)

用过android的同学对于handler应该都很了解,用起来比较方便。这里用rust设计了一个简单的rust。

1.处理接口

pub trait ProcessMessage {fn handleMessage(&self,msg:Message);
}

2.Message结构体

pub struct Message {pub what:u32,pub arg1:i32,pub arg2:i32,pub next_time:u64,pub next:Option<Rc<RefCell<Message>>>, //1pub target:Option<Arc<Box<dyn ProcessMessage>>>//2
}

1.指向下一个message,整个消息队列采用链表结构,使用option主要是为了确认是否还有message

2.target是一个回调实现,每个message都需要带有target,这样message就能由指定的handler处理了。

关键函数

impl Message {....fn execute(&self) {match &self.target {None=> {},Some(handler) => {handler.handleMessage(Message{what:self.what,arg1:self.arg1,arg2:self.arg2,next_time:self.next_time,next:None,target:None})} //1}}
}

1.message处理的时候调用了ProcessMessage,这里主要考虑到使用的方便(不要再用什么unwrap),所以传出去的数据重新构造了一个新数据,性能上会有损耗

3.消息队列

pub struct MessageQueue {head:Mutex<Message>,//1cond:Condvar//2
}

1.消息队列头,为了减少option,这里规定了第一个消息一直不使用,所有消息从head的next开始排队

2.cond:如果没有消息,或者消息需要延迟发送,则使用这个做等待处理。每次有新消息加入的时候,重新针对消息队列排序,然后cond.notify一下,唤醒等待线程

4.Looper

struct Looper {queue:Arc<RefCell<MessageQueue>>,
}

Looper主要就是一个queue,

关键函数:

fn loop_self(&self) {loop {println!("loop self start");let msg = self.queue.clone().try_borrow_mut().unwrap().dequeue_message();//1println!("loop self trace1");match msg {None=>{},Some(m) => {let _msg = m.clone();_msg.try_borrow_mut().unwrap().execute();//2}}}}

这里loop_self主要是给一个线程做死循环用的。

1.从queue中获取message,如果没有则会在这里卡死

2.message执行

5.HandlerThread

struct HandlerThread {looper:Arc<Looper>
}

主要函数:

fn start(&self) {loop {self.looper.loop_self();//1}}

1.循环处理messagequeue的数据,这个start函数最后会在一个线程中调用

6.Handler

pub struct Handler {queue:Arc<RefCell<MessageQueue>>,processor:Arc<Box<dyn ProcessMessage>>,
}

关键函数:

pub fn new(processor:Box<dyn ProcessMessage>)->Self {println!("handler construct trace1", );let handler_th = HandlerThread::new();let handler = Handler {queue:handler_th.get_looper().queue.clone(),processor:Arc::new(processor)};println!("handler construct trace2", );thread::spawn(move||{handler_th.start();//1});handler}

1.上面数据结构的消息队列是在这里被驱动的。

测试代码:

struct MyProcessor {}impl ProcessMessage for MyProcessor {fn handleMessage(&self,msg:Message) {println!("msg is {}",msg.what);//thread::sleep(Duration::from_secs(10));}
}pub fn test_handler_send_empty_message() {println!("test_handler_send_empty_message trace1");let h = handler::Handler::new(Box::new(MyProcessor{}));println!("test_handler_send_empty_message trace2");h.send_empty_message(1);h.send_empty_message_delayed(2,1000);thread::sleep(Duration::from_secs(100));
}

全代码:

use std::borrow::Borrow;
use std::borrow::BorrowMut;
use std::cell::RefCell;
use std::cell::Cell;
use std::ptr::NonNull;use std::rc::Rc;
use std::sync::Arc;
use std::sync::{Mutex,Condvar};
use std::thread;
use std::time::Duration;use tokio::time::Interval;use crate::system;pub trait ProcessMessage {fn handleMessage(&self,msg:Message);
}//---- Message ----
pub struct Message {pub what:u32,pub arg1:i32,pub arg2:i32,pub next_time:u64,pub next:Option<Rc<RefCell<Message>>>,pub target:Option<Arc<Box<dyn ProcessMessage>>>
}impl Message {pub fn new(what:u32)->Self {Message {what:what,arg1:0,arg2:0,next_time:0,next:None,target:None}}fn set_next(&mut self,next:Message)->&mut Self {self.next = Some(Rc::new(RefCell::new(next)));//Some(RefCell::new(Rc::new(Box::new(next))));self}// pub fn set_target(&mut self,target:Box<dyn ProcessMessage>)->&mut Self {//     self.target = Some(target);//     self// }fn execute(&self) {match &self.target {None=> {},Some(handler) => {handler.handleMessage(Message{what:self.what,arg1:self.arg1,arg2:self.arg2,next_time:self.next_time,next:None,target:None})}}}
}//---- MessageQueue ----
pub struct MessageQueue {head:Mutex<Message>,cond:Condvar
}impl MessageQueue {pub fn new()->Self {MessageQueue {head:Mutex::new(Message::new(0)),cond:Condvar::new()}}pub fn dequeue_message(&mut self)->Option<Rc<RefCell<Message>>> {println!("dequeue_message start");loop {let mut head = self.head.lock().unwrap();println!("dequeue_message trace1");match head.next.clone() {None => {println!("dequeue_message trace2");self.cond.wait(head);continue;},Some(msg)=>{let next_time = msg.try_borrow().unwrap().next_time;println!("msg next time is {},current is {}", next_time,system::currentMillis());if next_time <=  system::currentMillis() {head.next = msg.try_borrow().unwrap().next.clone();return Some(msg.clone());}self.cond.wait_timeout(head,Duration::from_millis(next_time - system::currentMillis()));                   }}}}pub fn enqueue_message(&mut self,mut msg:Message) {let mut head = self.head.lock().unwrap();println!("enqueue message trace1", );if let Some(v) = &head.next {let mut prev = v.clone();let mut current = v.clone();let mut pos:u32 = 0;println!("enqueue message trace2", );loop {if current.try_borrow().unwrap().next_time > msg.next_time {println!("enqueue message trace3", );if pos == 0 {println!("enqueue message trace4", );msg.next = Some(current);head.next = Some(Rc::new(RefCell::new(msg)));} else {println!("enqueue message trace5", );msg.next = Some(current);prev.try_borrow_mut().unwrap().next = Some(Rc::new(RefCell::new(msg)));}self.cond.notify_one();return;} else {println!("enqueue message trace6", );pos += 1;let mut is_none = false;match current.try_borrow().unwrap().next {None => {is_none = true;},Some(_) => {}}if is_none {current.try_borrow_mut().unwrap().next =  Some(Rc::new(RefCell::new(msg)));self.cond.notify_one();return;}prev = current.clone();let tmp: Rc<RefCell<Message>> = current.try_borrow_mut().unwrap().next.clone().unwrap().clone();current = tmp;}}} else {println!("enqueue message trace8", );head.next = Some(Rc::new(RefCell::new(msg)));self.cond.notify_one();return}}
}//
struct Looper {queue:Arc<RefCell<MessageQueue>>,
}impl Looper {fn new()->Self {Looper {queue:Arc::new(RefCell::new(MessageQueue::new())),}}fn get_queue(&self)->Arc<RefCell<MessageQueue>> {self.queue.clone()}fn loop_self(&self) {loop {println!("loop self start");let msg = self.queue.clone().try_borrow_mut().unwrap().dequeue_message();println!("loop self trace1");match msg {None=>{},Some(m) => {let _msg = m.clone();_msg.try_borrow_mut().unwrap().execute();}}}}
}
struct HandlerThread {looper:Arc<Looper>
}impl HandlerThread {fn new()->Self {HandlerThread {looper:Arc::new(Looper::new()),}}fn new_with_looper(looper:Arc<Looper>)->Self {HandlerThread {looper:looper.clone(),}}fn start(&self) {loop {self.looper.loop_self();}}pub fn get_looper(&self)->Arc<Looper> {self.looper.clone()}
}pub struct Handler {queue:Arc<RefCell<MessageQueue>>,processor:Arc<Box<dyn ProcessMessage>>,
}unsafe impl Send for HandlerThread{}impl Handler {pub fn new(processor:Box<dyn ProcessMessage>)->Self {println!("handler construct trace1", );let handler_th = HandlerThread::new();let handler = Handler {queue:handler_th.get_looper().queue.clone(),processor:Arc::new(processor)};println!("handler construct trace2", );thread::spawn(move||{handler_th.start();});handler}pub fn send_empty_message(&self,what:u32) {println!("send_empty_message start");let mut msg = Message::new(what);msg.target = Some(self.processor.clone());self.queue.try_borrow_mut().unwrap().enqueue_message(msg);}pub fn send_empty_message_delayed(&self,what:u32,interval:u64) {let mut msg = Message::new(what);msg.next_time = system::currentMillis() + interval;msg.target = Some(self.processor.clone());self.queue.try_borrow_mut().unwrap().enqueue_message(msg);}
}

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

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

相关文章

Java:设计模式

文章目录 参考简介工厂模式简单工厂模式工厂方法模式抽象工厂模式总结 单例模式预加载懒加载线程安全问题 策略模式 参考 知乎 简介 总体来说设计模式分为三类共23种。 创建型模式&#xff0c;共五种&#xff1a;工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模…

Function与Module的差异与应用场景,symbolic() 和 forward() 是什么关系?

Function与Module的差异与应用场景 Function与Module都可以对pytorch进行自定义拓展&#xff0c;使其满足网络的需求&#xff0c;但这两者还是有十分重要的不同&#xff1a; Function一般只定义一个操作&#xff0c;因为其无法保存参数&#xff0c;因此适用于激活函数、pooli…

Unity构建详解(1)——SBP介绍

【前言】 Unity的资源工作流程分为导入、创建、构建、分发、加载。我们说的是其中的构建步骤。 构建是指将项目工程中的资源文件和代码整合程可执行文件的过程&#xff0c;构建的结果是生成可执行文件&#xff0c;在win平台上是exe&#xff0c;在Android平台上是apk&#xff…

基于浏览器localStorage作为数据库完成todolsit项目

一、文章内容 TodoList结构搭建HTML代码 TodoList样式编写Css代码 TodoList行为表现JavaScript代码 二、项目展示 项目介绍 Todolist是一个基于B/S模式开发的待办事项软件&#xff0c;主要功能是离线记录用户的待办事项和已经完成的事情&#xff0c;基于htmlcssjs实现&am…

Superset二次开发之PostgreSQL 存储库介绍

Apache Superset 使用 PostgreSQL 作为其默认的元数据数据库,来存储关于数据源、图表、仪表盘、用户及其权限等信息。下面是列出的一些主要表的功能和作用的简介: 权限和角色 ab_permission: 存储权限,如“可以访问仪表板”、“可以执行SQL查询”等。ab_permission_view: 将…

Mysql——索引下推

MySQL的索引下推&#xff08;Index Condition Pushdown, ICP&#xff09;是一种查询优化技术&#xff0c;它允许MySQL在存储引擎层执行部分WHERE子句中的过滤条件&#xff0c;而非全部在MySQL服务器层执行。这使得在扫描索引过程中就可以剔除不满足条件的记录&#xff0c;从而减…

【C++】---string的模拟

【C】---string的模拟 一、string类实现1.string类的构造函数2.swap&#xff08;&#xff09;函数3.拷贝构造函数4.赋值运算符重载5.析构6.迭代器7.operator[ ]8.size9.c_str&#xff08;&#xff09;10.reserve&#xff08;&#xff09;11.resize&#xff08;&#xff09;12.p…

flutter 局部view更新,dialog更新进度,dialog更新

局部更新有好几种方法&#xff0c;本次使用的是 StatefulBuilder 定义 customState去更新对话框内容 import package:flutter/cupertino.dart; import package:flutter/material.dart;class ProgressDialog {final BuildContext context;BuildContext? dialogContext;double _…

【DL经典回顾】激活函数大汇总(四十一)(SinReLU附代码和详细公式)

激活函数大汇总(四十一)(SinReLU附代码和详细公式) 更多激活函数见激活函数大汇总列表 一、引言 欢迎来到我们深入探索神经网络核心组成部分——激活函数的系列博客。在人工智能的世界里,激活函数扮演着不可或缺的角色,它们决定着神经元的输出,并且影响着网络的学习能…

Oracle函数6—递归查询(start with...connect by、sys_connect_by_path、level)

文章目录 一、准备数据二、基本使用三、level函数四、获取完整的全树路径 一、准备数据 创建表 CREATE TABLE TEST_ORG (ID VARCHAR2(64) NOT NULL PRIMARY KEY,NAME VARCHAR2(200),PARTEN_ID VARCHAR2(64) ); comment on column TEST_ORG.ID is 主键; comment on column TES…

C语言经典例题(2) --- 阶乘、斐波那契数、9*9乘法表、字符串逆序、求和

文章目录 1.求n的阶乘。(不考虑溢出)2.求第n个斐波那契数。&#xff08;不考虑溢出&#xff09;3.屏幕上输出9*9乘法口诀表4.字符串逆序(递归实现)5.计算一个数的每位之和(递归实现) 1.求n的阶乘。(不考虑溢出) #include <stdio.h>int fac(int n);int main() {int n 0;…

8节点空间壳单元Matlab有限元编程 | 曲壳单元 | 模态分析 | 3D壳单元 | 板壳理论| 【源代码+理论文本】

专栏导读 作者简介&#xff1a;工学博士&#xff0c;高级工程师&#xff0c;专注于工业软件算法研究本文已收录于专栏&#xff1a;《有限元编程从入门到精通》本专栏旨在提供 1.以案例的形式讲解各类有限元问题的程序实现&#xff0c;并提供所有案例完整源码&#xff1b;2.单元…

Mysql的行级锁

MySQL 中锁定粒度最小的一种锁&#xff0c;是 针对索引字段加的锁 &#xff0c;只针对当前操作的行记录进行加锁。 行级锁能大大减少数据库操作的冲突。其加锁粒度最小&#xff0c;并发度高&#xff0c;但加锁的开销也最大&#xff0c;加锁慢&#xff0c;会出现死锁。行级锁和存…

数据结构面试常见问题之Insert or Merge

&#x1f600;前言 本文将讨论如何区分插入排序和归并排序两种排序算法。我们将通过判断序列的有序性来确定使用哪种算法进行排序。具体而言&#xff0c;我们将介绍判断插入排序和归并排序的方法&#xff0c;并讨论最小和最大的能区分两种算法的序列长度。 &#x1f3e0;个人主…

Postman接口做关联测试的方法步骤

应用场景 假设下一个接口登录需要上一个接口的返回值&#xff0c;例如请求需要先登录获取到token&#xff0c;下一个请求要携带对应的token才能进行请求 方法&#xff1a;通过设置全局变量/环境变量 方法一&#xff1a;设置全局变量 1.先请求登录接口&#xff0c;请求成功之后…

力扣Lc20--- 202.快乐数(java版)-2024年3月20日

1.题目 2.知识点 &#xff08;1&#xff09;while (seen.contains(n) false) { // 循环体 } 与 !seen.contains(n) 等同 &#xff08;2&#xff09; 当传入数字 19 给 isHappy(19) 方法时&#xff0c;下面是每一行代码的执行过程&#xff1a; 初始化一个空的 HashSet&#…

32.网络游戏逆向分析与漏洞攻防-游戏网络通信数据解析-网络数据分析原理与依据

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果 内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;31.其它消息的实…

(七)事件组

一、概念 &#xff08;1&#xff09;用于实现任务与任务、任务与中断之间通信和同步&#xff0c;无数据传输 &#xff08;2&#xff09;不同于信号量的是&#xff0c;信号量是一对一的&#xff0c;而事件可以是一对多和多对一的&#xff0c;即一个任务等待多个事件或多个任务等…

el-table的border属性失效问题解决方案

目录 问题&#xff1a; 使用的代码&#xff1a; 官方文档的说明&#xff1a; 可能的问题所在&#xff1a; 关于使用了作用域插槽&#xff1a; a.自定义内容的样式覆盖&#xff1a; b.表格结构的改变&#xff1a; 解决方案&#xff1a; 通过css样式解决&#xff1a; 下面…

打流仪/网络测试仪这个市场还能怎么卷?

#喝了点&#xff0c;码点字# 以下为个人观点&#xff0c;看看就好&#xff0c;如有冒犯&#xff0c;私信删稿 都有哪些厂商在做打流仪/网络测试仪 -洋品牌&#xff1a;思博伦/Viavi-Spirent&#xff0c;是德/Keysight-Ixia&#xff0c;信雅纳/Lecroy-Xena&#xff0c; -国产…