如何在Rust中实现可中断睡眠 解决休眠无法响应SIGINT信号问题
Rust 可中断休眠实现方案
原生标准库实现思路
Rust 标准库没有直接提供可被信号中断的休眠接口,但可以通过std::sync::Condvar(条件变量)搭配原子状态标记实现需求,核心逻辑是将固定时长的休眠替换为带超时的条件变量等待,收到中断信号时主动唤醒等待流程即可。
示例代码如下:
use std::sync::{Arc, Condvar, Mutex}; use std::time::Duration; fn main() { // 定义终止状态元组:(是否触发终止, 条件变量) let terminate_flag = Arc::new((Mutex::new(false), Condvar::new())); let flag_clone = terminate_flag.clone(); // 注册ctrlc中断处理逻辑 ctrlc::set_handler(move || { let (lock, cvar) = &*flag_clone; let mut terminate = lock.lock().unwrap(); *terminate = true; // 唤醒所有等待条件变量的线程 cvar.notify_all(); }).expect("中断信号处理器注册失败"); let (lock, cvar) = &*terminate_flag; loop { // 此处替换为你需要定期执行的业务逻辑 println!("执行定时操作"); // 带超时的条件等待:最长等待2秒,收到终止信号时直接唤醒 let (lock_result, timeout_result) = cvar .wait_timeout_while( lock.lock().unwrap(), Duration::from_secs(2), |&mut should_terminate| !should_terminate ) .unwrap(); // 检查是否触发终止信号,是则直接退出循环 if *lock_result { println!("收到中断信号,程序退出"); break; } } }
注意:Condvar 本身存在虚假唤醒的特性,上述实现通过wait_timeout_while的状态判断逻辑自动规避了该问题,不需要额外处理边界情况。
std::thread::sleep不可中断的原因
Rust 的sleep实现和C语言的sleep行为不同:C语言的sleep在被信号中断时会直接返回剩余休眠时长,上层可以感知到中断事件;而Rust标准库的sleep在底层系统调用返回EINTR(被信号中断)错误时,会自动计算剩余休眠时长并重试系统调用,所以上层逻辑感知不到中断,会一直休眠到总时长达标才返回。
其他可选实现方案
- 如果项目使用Tokio等异步运行时,可以直接用
tokio::time::sleep和信号监听Future搭配select!宏实现中断休眠,代码逻辑会更简洁。
内容的提问来源于stack exchange,提问作者Eolien55
相关产品推荐
相关产品推荐

