在Rust中实现Linux CLOCK_MONOTONIC式的绝对时间等待
在Rust中实现基于单调时钟的异步等待功能
需求背景
需要在Linux平台的Rust程序中,等待系统单调时钟(统计系统启动后的流逝时间)达到指定值,对应C语言的实现代码如下:
void sleep_until_monotonic(int64_t ts) { int fd = timerfd_create(CLOCK_MONOTONIC, 0); struct itimerspec its = { .it_value = { .tv_sec = ts }}; timerfd_settime(fd, TFD_TIMER_ABSTIME, &its, NULL); struct pollfd pfd = { .fd = fd, .events = POLLIN }; poll(&pfd, 1, -1); close(fd); }
期望的Rust异步API形式:
some_lib::sleep_until_monotonic(1234).await?
实现方案
1. Linux专属异步实现
直接调用Linux系统的timerfd系列API,结合Tokio的异步IO封装,实现无阻塞的异步等待:
依赖配置
在Cargo.toml中添加:
[dependencies] tokio = { version = "1.0", features = ["full"] } libc = "0.2"
代码实现
use libc::{c_long, timerfd_create, timerfd_settime, CLOCK_MONOTONIC, TFD_TIMER_ABSTIME, itimerspec, timespec}; use tokio::io::AsyncFd; use std::os::unix::io::FromRawFd; use std::io; pub async fn sleep_until_monotonic(ts_sec: i64) -> io::Result<()> { // 创建基于单调时钟的timerfd let fd = unsafe { timerfd_create(CLOCK_MONOTONIC, 0) }; if fd == -1 { return Err(io::Error::last_os_error()); } // 设置绝对时间触发的定时器 let its = itimerspec { it_value: timespec { tv_sec: ts_sec as c_long, tv_nsec: 0, }, it_interval: timespec { tv_sec: 0, tv_nsec: 0, }, }; let res = unsafe { timerfd_settime(fd, TFD_TIMER_ABSTIME, &its, std::ptr::null_mut()) }; if res == -1 { let err = io::Error::last_os_error(); unsafe { libc::close(fd) }; return Err(err); } // 异步等待timerfd可读(定时器触发) let mut async_fd = unsafe { AsyncFd::from_raw_fd(fd) }; let _guard = async_fd.readable().await?; // 读取timerfd的计数,避免资源泄漏 let mut buf = [0u8; 8]; let _ = async_fd.read(&mut buf)?; Ok(()) }
2. 跨平台异步实现
使用time crate获取跨平台的单调时钟时间,结合Tokio的sleep实现异步等待,支持Linux、Windows、macOS等主流平台:
依赖配置
在Cargo.toml中添加:
[dependencies] tokio = { version = "1.0", features = ["full"] } time = { version = "0.3", features = ["std", "clock"] }
代码实现
use time::{Clock, Duration}; use tokio::time::sleep; use std::io; pub async fn sleep_until_monotonic(ts_sec: i64) -> io::Result<()> { let target_duration = Duration::seconds(ts_sec); // 获取当前单调时钟从系统启动到现在的流逝时长 let now_duration = Clock::Monotonic.instant()?.duration_since_epoch()?; // 如果目标时间已过,直接返回 if target_duration <= now_duration { return Ok(()); } // 计算需要等待的时长并异步睡眠 let wait_duration = target_duration - now_duration; sleep(wait_duration).await; Ok(()) }
内容的提问来源于stack exchange,提问作者jforberg
相关产品推荐
相关产品推荐

