< 返回版块

kipade 发表于 2025-04-16 16:55

Tags:serialport;send;sync

我在学习rust过程中用到了serialport库来进行串口读写,需求很简单,我创建一个子线程,在子线程中只读;然后,在主线程中写,代码如下: use std::io::{self, Write}; use std::sync::{Arc, RwLock}; use std::thread; use std::time::Duration; use serialport;

fn main() { // 配置串口参数 let port_name = "/dev/ttyUSB0"; // 修改为你的设备路径(Windows: "COM1")

// 打开串口(使用读写锁包装)
let port = serialport::new(port_name, 9600).open()
    .expect("Failed to open serial port");
let port = Arc::new(RwLock::new(port));

// 克隆端口到子线程用于读取
let read_port = Arc::clone(&port);
let reader = thread::spawn(move || {
    let mut buffer = [0u8; 256];
    loop {
        // 获取读锁(允许多线程并发读)
        let port = read_port.read().unwrap();
        match port.read(&mut buffer) {
            Ok(bytes_read) => {
                if bytes_read > 0 {
                    let data = &buffer[..bytes_read];
                    println!("Received: {}", String::from_utf8_lossy(data));
                }
            }
            Err(ref e) if e.kind() == io::ErrorKind::TimedOut => {}
            Err(e) => eprintln!("Read error: {}", e),
        }
        // 读锁在此处自动释放
    }
});

// 主线程用于写入
let write_port = Arc::clone(&port);
loop {
    // 从标准输入读取数据
    print!("Enter message to send (or 'exit' to quit): ");
    io::stdout().flush().unwrap();
    let mut input = String::new();
    io::stdin().read_line(&mut input).unwrap();

    // 处理退出命令
    if input.trim() == "exit" {
        break;
    }

    // 获取写锁(独占访问)
    let mut port = write_port.write().unwrap();
    port.write_all(input.as_bytes())
        .expect("Failed to write to port");
    // 写锁在此处自动释放
}

// 等待读取线程结束
reader.join().unwrap();

}

这是deepseek帮我写然后我修改得到,但是的确表达了我的意愿.但是,这段代码编译不通过: error[E0277]: dyn SerialPort cannot be shared between threads safely --> src/main.rs:18:32 | 18 | let reader = thread::spawn(move || { | __________________-------------_^ | | | | | required by a bound introduced by this call 19 | | let mut buffer = [0u8; 256]; 20 | | loop { ... | 35 | | }); | |_____^ dyn SerialPort cannot be shared between threads safely 如果把这里的RwLock换成Mutex,再做对应的差异修改是可以的.但是,不符合我的期望,因为如果用Mutex,意味着读的时候不能写,写的时候不能读,这显然不是我期望的. 看了serialport的文档,SerialPort这个Trait的确只Send,没有Sync,所以按Rust的语法要求这里锁的确是不可少的,但因为全程两个线程一个读一个写,必须是RwLock. 面对这个问题,该如何修改呢?我这个新手又找不到答案了

评论区

写评论
作者 kipade 2025-04-16 18:06

我的确把问题复杂化了,我反思了一下,原因在于对"同时只能有对一个绑定的可变借用"的理解上,这里直接生出两个可变的绑定,还就真的互不干扰了

langzi.me 2025-04-16 18:03

三人行必有我师,互相帮助,加油

作者 kipade 2025-04-16 17:51

谢谢帮忙,我新手,目前还只会从通过文档结合所学习到的语法写这个代码. 这么看的话,我和DeepSeek一样,把问题搞复杂了

langzi.me 2025-04-16 17:34

这不是项目下有读写的例子。 port clone一下就可以了。 不用自己处理。 fn main() { // Open the first serialport available. let port_name = &serialport::available_ports().expect("No serial port")[0].port_name; let mut port = serialport::new(port_name, 9600) .open() .expect("Failed to open serial port");

// Clone the port
let mut clone = port.try_clone().expect("Failed to clone");

// Send out 4 bytes every second
thread::spawn(move || loop {
    clone
        .write_all(&[5, 6, 7, 8])
        .expect("Failed to write to serial port");
    thread::sleep(Duration::from_millis(1000));
});

// Read the four bytes back from the cloned port
let mut buffer: [u8; 1] = [0; 1];
loop {
    match port.read(&mut buffer) {
        Ok(bytes) => {
            if bytes == 1 {
                println!("Received: {:?}", buffer);
            }
        }
        Err(ref e) if e.kind() == io::ErrorKind::TimedOut => (),
        Err(e) => eprintln!("{:?}", e),
    }
}

}

1 共 4 条评论, 1 页