Rust结构体中分离线程循环的GPIO计数实现问题
Rust树莓派GPIO引脚检测与并发计数实现
核心方案
用Arc<Mutex<u32>>实现跨线程安全的计数共享,GPIO输入引脚由检测线程独占持有(InputPin不支持跨线程共享),主线程通过互斥锁安全读取计数。
完整代码示例
首先在Cargo.toml中添加依赖:
[dependencies] rppal = "0.14.0"
src/main.rs代码:
use rppal::gpio::{Gpio, InputPin, PullUpDown}; use std::sync::{Arc, Mutex}; use std::thread; use std::time::Duration; // 封装GPIO计数逻辑的结构体 struct GpioEdgeCounter { count: Arc<Mutex<u32>>, _worker_thread: thread::JoinHandle<()>, } impl GpioEdgeCounter { // 构造函数:传入引脚编号,初始化计数器并启动检测线程 fn new(pin_number: u8) -> Result<Self, Box<dyn std::error::Error>> { // 初始化GPIO控制器,获取指定引脚并设置为输入模式 let gpio = Gpio::new()?; let mut pin = gpio.get(pin_number)?.into_input(); // 根据硬件连接设置上拉/下拉,这里设置为下拉(引脚默认低电平) pin.set_pull_up_down(PullUpDown::PullDown); // 创建线程安全的共享计数变量 let count = Arc::new(Mutex::new(0u32)); let count_clone = Arc::clone(&count); // 启动检测线程,转移引脚所有权到线程内部 let worker_thread = thread::spawn(move || { loop { // 等待引脚上升沿(低→高电平),超时1秒后继续循环 match pin.wait_for_rising_edge(Duration::from_secs(1)) { Ok(true) => { // 成功检测到上升沿,加锁并递增计数 let mut counter = count_clone.lock().unwrap(); *counter += 1; println!("检测到上升沿,当前计数:{}", *counter); } Ok(false) => continue, // 超时,继续等待 Err(e) => { eprintln!("引脚检测失败:{}", e); break; } } } }); Ok(Self { count, _worker_thread: worker_thread, }) } // 安全获取当前计数的方法 fn current_count(&self) -> u32 { *self.count.lock().unwrap() } } fn main() -> Result<(), Box<dyn std::error::Error>> { // 初始化计数器,使用引脚17(根据实际硬件修改) let counter = GpioEdgeCounter::new(17)?; // 主线程循环读取计数 loop { println!("主线程读取计数:{}", counter.current_count()); thread::sleep(Duration::from_secs(2)); } }
变量声明与循环逻辑说明
- 引脚变量
pin:在构造函数中初始化后,通过move关键字转移给检测线程,让线程独占引脚所有权——因为InputPin不实现Synctrait,无法跨线程共享,必须由单个线程持有。 - 计数变量
count:用Arc<Mutex<u32>>包裹,Arc允许线程间共享所有权,Mutex保证同一时刻只有一个线程能访问计数,彻底避免数据竞争。构造函数中克隆一份Arc给检测线程,实现双线程对计数的安全访问。 - 检测循环:使用
wait_for_rising_edge阻塞等待引脚上升沿,比主动轮询更高效;检测到上升沿时,先获取Mutex锁,再递增计数,确保操作原子性。 - 主线程读取:通过
current_count方法获取锁并读取计数,保证读取到的是最新的有效值。
内容的提问来源于stack exchange,提问作者reeslabree
相关产品推荐
相关产品推荐

