Rust code: demo of message system

Requirements:

  1. Multi-threads receive/send messages

  2. Use mailbox ID to find message channel

Implementation:

  1. use mpsc lib for message channel

  2. use hash table for ID to message channel mapping

Limitation:

  1. mpsc channel has sender and receiver, but only sender could be clone() in rust. So only sender could be saved in hash table. refer to limitation 2.

  2. To share hash table among tasks, need Arc and Mutex for hash table. But the lock range impacts sender's function. To make multi-tasks can work at the same time( not need wait for one task finishing all job then release lock), we need drop the lock of hash table. And only sender could support this drop.

Code:

  1. message_lib.rs
rust 复制代码
use once_cell::sync::Lazy;

use std::vec::Vec;
use std::collections::HashMap;
use std::sync::{Arc, Mutex, mpsc};
//use std::thread;
//use std::time::Duration;


pub struct MessageHeader{
    pub src_id: u32,
    pub dest_id: u32,
    pub primitive: u32,
    pub param: Vec<u32>,
}

// Define a struct to hold the senders with IDs
pub struct MailboxRegistry {
    senders: HashMap<u32, mpsc::Sender<MessageHeader>>,
}

impl MailboxRegistry {
    pub fn new() -> Self {
        MailboxRegistry {
            senders: HashMap::new(),
        }
    }

    pub fn add_mailbox(&mut self, id: u32, sender: mpsc::Sender<MessageHeader>) {
        self.senders.insert(id, sender);
    }

    pub fn get_mailbox_sender(&self, id: u32) -> Option<&mpsc::Sender<MessageHeader>> {
        self.senders.get(&id)
    }
}

pub static MAILBOX_MATRIX: Lazy<Arc<Mutex<MailboxRegistry>>> = Lazy::new(|| {
    Arc::new(Mutex::new(MailboxRegistry::new()))
});

pub struct MailboxSystem {
    //pub ch_matrix : MailboxRegistry,
}

impl MailboxSystem {

    pub fn create_mailbox_channel(id: u32) -> mpsc::Receiver<MessageHeader> {
        let (sender, receiver) = mpsc::channel();
        {
            MAILBOX_MATRIX.lock().unwrap().add_mailbox(id, sender);
        }
        println!("Created channel ID {}", id);
        return receiver;
    }

    pub fn mb_send_message(id:u32, msg:MessageHeader)
    {
        println!("try to send message from sender ID {}, trying to get lock()", id);
        let mailbox_registry = MAILBOX_MATRIX.lock().unwrap();
        if let Some(sender) = mailbox_registry.get_mailbox_sender(id) { //self.get_mailbox_channel_sender(id) {
            /*unlock MAILBOX_MATRIX here*/
            let sender_ref = sender.clone();
            drop(mailbox_registry);
            /*then send message*/
            sender_ref.send(msg).unwrap();
            println!("Sent message from sender ID {}", id);
        } else {
            println!("No sender found for ID {}", id);
        }
    }

}

pub fn print_message(msg:&MessageHeader)
{
    println!("messge src {}",msg.src_id);
    println!("messge dest {}",msg.dest_id);
    println!("messge primitive {}",msg.primitive);
    for element in &(msg.param) {
        println!("Element: {}", element);
    }
}
  1. main.rs
rust 复制代码
use std::vec::Vec;
use std::sync::{mpsc};
use std::thread;
use std::time::Duration;

mod message_lib;
use crate::message_lib::{MailboxSystem,MessageHeader,print_message};

pub fn thread_send_message(mailbox_id:u32, src_id:u32, dest_id:u32, primitive:u32)
{
    let mut msg = MessageHeader {
        src_id : src_id,
        dest_id : dest_id,
        primitive : primitive,
        param : Vec::new(),
    };
    msg.param.push(primitive*2);
    MailboxSystem::mb_send_message(mailbox_id, msg);
}
pub fn thread_recv_message(receiver:&mpsc::Receiver<MessageHeader>) -> u32
{
    match receiver.recv() {
        Ok(msg) => {
            print_message(&msg);
            return msg.primitive;
        }
        Err(_) => {
            println!("Receiver fail");
            return 0;
        }
    }
}

fn main() {
    let thread_recv = thread::spawn( move || {
            println!("start Receiver");
            let mut tx_1_done = 0;
            let mut tx_2_done = 0;
            let receiver = MailboxSystem::create_mailbox_channel(1);
            loop {
                let count = thread_recv_message(&receiver);
                if count == 9999 {
                    tx_1_done = 1;
                }
                if count == 8888 {
                    tx_2_done = 1;
                }
                if tx_1_done == 1 && tx_2_done == 1 {
                    break;
                }
            }
    });
    thread::sleep(Duration::from_secs(1));
    let thread_send1 = thread::spawn( move || {
        println!("start Sender1");
        let mailbox_id = 1;
        let mut primitive = 0;
        for _ in 0..500 {
            primitive += 1;
            thread_send_message(mailbox_id,8,9,primitive);
        }
        primitive = 9999;
        thread_send_message(mailbox_id,8,9,primitive);
        thread::sleep(Duration::from_secs(1));
    });
    let thread_send2 = thread::spawn( move || {
        println!("start Sender2");
        let mailbox_id = 1;
        let mut primitive = 500;
        for _ in 0..400 {
            primitive += 1;
            thread_send_message(mailbox_id,12,9,primitive);
        }
        primitive = 8888;

        thread_send_message(mailbox_id,8,9,primitive);
        thread::sleep(Duration::from_secs(1));
    });
    match thread_send1.join() {
        Ok(_) => println!("The send thread1 has finished."),
        Err(_) => println!("An error occurred while joining the thread"),
    }
    match thread_send2.join() {
        Ok(_) => println!("The send thread2 has finished."),
        Err(_) => println!("An error occurred while joining the thread"),
    }
    match thread_recv.join() {
        Ok(_) => println!("The recv thread has finished."),
        Err(_) => println!("An error occurred while joining the thread:"),
    }

}
  1. cargo.toml
rust 复制代码
[package]
name = "message"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
once_cell = "1.4.0"

[lib]
path = "src/message_lib.rs"
相关推荐
Rust研习社9 小时前
组合真的优于继承吗?为什么 Rust 和 Go 都拥抱组合舍弃继承?
后端·rust·编程语言
红尘散仙1 天前
想写一个像样的终端 App?试试把 React 的开发体验搬进 Rust TUI
前端·rust
vivo互联网技术1 天前
从 Web 到桌面:基于 Tauri 2.0 + Vue 3 打造 vivo 线下门店「大头贴」拍照体验系统
前端·rust
Rust研习社2 天前
这 8 个 Rust 学习资源值得每个新手收藏起来
后端·rust·编程语言
LDR0062 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术2 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript
码云数智-园园2 天前
C++20 Modules 模块详解
java·开发语言·spring
swordbob2 天前
NIO的channel中什么是 fd(File Descriptor,文件描述符)
java·开发语言·nio
源分享2 天前
Java线程同步的多种实现方法(非常详细)
java·开发语言·jvm
Luminous.2 天前
C语言--day30
c语言·开发语言