Rust串口通信多线程写入冻结问题求助
Rust串口双线程读写阻塞问题解决
问题根源
serialport crate的try_clone()在Windows等平台并未创建完全独立的串口句柄,底层共享同步锁,导致读线程阻塞时写线程无法获取锁,进而冻结。另外,默认无超时配置会让读线程无限期阻塞,加剧问题。
修复方案
方案1:配置超时+优化读逻辑
为串口设置读写超时,改用批量读取替代bytes()遍历,避免线程长期占用锁:
use std::{ io::{stdin, stdout, Read, Write}, thread, time::Duration, }; fn main() { // 打开串口并设置读超时 let mut port = serialport::new("COM5", 9600) .timeout(Duration::from_millis(100)) .open() .unwrap(); // 显式设置写超时 port.set_write_timeout(Duration::from_millis(100)).unwrap(); let mut r_port = port.try_clone().unwrap(); // 读线程:批量读取,超时则循环重试 thread::spawn(move || { let mut read_buf = [0u8; 128]; loop { match r_port.read(&mut read_buf) { Ok(n) if n > 0 => { print!("{}", String::from_utf8_lossy(&read_buf[..n])); stdout().flush().unwrap(); } Ok(_) => {} // 无数据超时,继续循环 Err(e) => { eprintln!("读串口错误: {}", e); break; } } } }); // 主线程处理用户输入发送 loop { let mut input = String::new(); stdin().read_line(&mut input).unwrap(); match port.write(input.as_bytes()) { Ok(_) => {}, Err(e) => eprintln!("写串口错误: {}", e), } } }
方案2:用通道单线程处理串口
如果克隆句柄问题无法解决,改用主线程统一处理串口读写,通过mpsc通道转发用户输入:
use std::{ io::{stdin, stdout, Read, Write}, sync::mpsc::{self, Receiver, Sender}, thread, time::Duration, }; fn main() { let mut port = serialport::new("COM5", 9600) .timeout(Duration::from_millis(50)) .open() .unwrap(); // 创建通道,用于输入线程向主线程发送数据 let (tx, rx): (Sender<Vec<u8>>, Receiver<Vec<u8>>) = mpsc::channel(); // 用户输入线程:只负责读取控制台输入并发送到通道 thread::spawn(move || { loop { let mut input = String::new(); stdin().read_line(&mut input).unwrap(); tx.send(input.as_bytes().to_vec()).unwrap(); } }); // 主线程:同时处理串口读和通道数据发送 let mut read_buf = [0u8; 128]; loop { // 优先读取串口数据 match port.read(&mut read_buf) { Ok(n) if n > 0 => { print!("{}", String::from_utf8_lossy(&read_buf[..n])); stdout().flush().unwrap(); } _ => {} } // 尝试接收通道中的输入数据并发送 if let Ok(data) = rx.try_recv() { port.write(&data).unwrap(); } } }
额外检查项
- 确认Arduino代码使用
Serial.available()判断后再读取,避免串口缓冲区阻塞。 - Windows平台下,关闭程序后需等待几秒再重新运行,防止串口资源未释放。
内容的提问来源于stack exchange,提问作者JJtheJJpro
相关产品推荐
相关产品推荐

