1,场景总结
定时器类型 | 精度范围 | 适用场景 | 注意事项 |
---|---|---|---|
用户态信号定时器 | 秒级 | 简单任务调度、心跳检测 | 信号处理函数中不可调用非异步安全函数 |
timerfd+epoll | 纳秒级 | 高精度事件循环、多媒体处理 | 需要配合IO多路复用机制使用 |
内核timer_list | 毫秒级 | 设备驱动、硬件交互 | 基于jiffies时钟滴答 |
内核hrtimer | 微秒级 | 实时系统、性能监控 | 消耗更多CPU资源 |
用户态传统信号定时器 | 秒级 | 后台日志轮转、简单心跳检测等对精度要求不高的场景 | 需要配合IO多路复用机制使用 |
2,用户态使用
(1),监控日志
#include <sys/time.h>
#include <signal.h>
#include <unistd.h>
void timer_handler(int sig) {
static int count = 0;
KEIL_LOG(KERNEL_CTRL, "Timer expired %d times\n", ++count);
//printf("Timer expired %d times\n", ++count);
}
int main() {
struct sigaction sa;
struct itimerval timer;
// 设置信号处理函数
sa.sa_handler = &timer_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGALRM, &sa, NULL);
// 配置定时器(首次1秒后触发,之后每2秒触发)
timer.it_value.tv_sec = 1;
timer.it_value.tv_usec = 0;
timer.it_interval.tv_sec = 2;
timer.it_interval.tv_usec = 0;
setitimer(ITIMER_REAL, &timer, NULL);
while(1) pause(); // 保持进程运行
return 0;
}
(2),心跳包检测
#include <sys/timerfd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#define HEARTBEAT_INTERVAL 5
void send_heartbeat(int sockfd) {
const char *msg = "HEARTBEAT";
send(sockfd, msg, strlen(msg), 0);
}
int main() {
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
// 连接服务器代码省略...
int timer_fd = timerfd_create(CLOCK_MONOTONIC, 0);
struct itimerspec its = {
.it_value = {.tv_sec = HEARTBEAT_INTERVAL, .tv_nsec = 0},
.it_interval = {.tv_sec = HEARTBEAT_INTERVAL, .tv_nsec = 0}
};
timerfd_settime(timer_fd, 0, &its, NULL);
while(1) {
uint64_t exp;
read(timer_fd, &exp, sizeof(exp));
send_heartbeat(sockfd); // 每5秒发送心跳包
}
close(timer_fd);
return 0;
}
(3)timerfd+epoll实现高精度定时器采集传感器数据
#include <sys/timerfd.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <string.h>
#define SENSOR_PATH "/dev/temperature_sensor" // 传感器设备路径
#define POLL_INTERVAL_MS 200 // 采集间隔200ms
int read_sensor_data(int fd) {
char buf[32];
int ret = read(fd, buf, sizeof(buf));
if(ret > 0) {
printf("Sensor value: %.*s\n", ret, buf);
return 0;
}
return -1;
}
int main() {
// 打开传感器设备
int sensor_fd = open(SENSOR_PATH, O_RDONLY | O_NONBLOCK);
if(sensor_fd == -1) {
perror("open sensor failed");
return -1;
}
// 创建定时器
int timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
struct itimerspec its = {
.it_interval = {.tv_sec = 0, .tv_nsec = POLL_INTERVAL_MS * 1000000},
.it_value = {.tv_sec = 1, .tv_nsec = 0} // 首次1秒后触发
};
timerfd_settime(timer_fd, 0, &its, NULL);
// 创建epoll实例
int epoll_fd = epoll_create1(0);
struct epoll_event timer_ev = {
.events = EPOLLIN,
.data.fd = timer_fd
};
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, timer_fd, &timer_ev);
// 事件循环
while(1) {
struct epoll_event events[2];
int n = epoll_wait(epoll_fd, events, 2, -1);
for(int i=0; i<n; i++) {
if(events[i].data.fd == timer_fd) {
uint64_t exp;
read(timer_fd, &exp, sizeof(exp));
read_sensor_data(sensor_fd); // 定时读取传感器
}
}
}
close(timer_fd);
close(sensor_fd);
return 0;
}
3,内核态使用
(1)精度内核定时器(hrtimer) 适合需要微秒级精度的内核任任务
#include <linux/module.h>
#include <linux/hrtimer.h>
#include <linux/io.h>
#define REG_ADDR 0xFE200000 // 设备寄存器物理地址
#define CHECK_INTERVAL_NS 200000000 // 200ms间隔
static struct hrtimer hr_timer;
static void __iomem *reg_map;
enum hrtimer_restart timer_callback(struct hrtimer *timer) {
u32 reg_value = ioread32(reg_map);
printk(KERN_INFO "Device reg value: 0x%x\n", reg_value);
hrtimer_forward_now(timer, ns_to_ktime(CHECK_INTERVAL_NS));
return HRTIMER_RESTART;
}
static int __init timer_init(void) {
// 映射硬件寄存器
reg_map = ioremap(REG_ADDR, sizeof(u32));
if (!reg_map) {
printk(KERN_ERR "Failed to map hardware register\n");
return -ENOMEM;
}
// 初始化高精度定时器
hrtimer_init(&hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
hr_timer.function = &timer_callback;
hrtimer_start(&hr_timer, ns_to_ktime(CHECK_INTERVAL_NS), HRTIMER_MODE_REL);
printk(KERN_INFO "Hardware monitor module loaded\n");
return 0;
}
static void __exit timer_exit(void) {
hrtimer_cancel(&hr_timer);
iounmap(reg_map);
printk(KERN_INFO "Module unloaded\n");
}
module_init(timer_init);
module_exit(timer_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("YourName");
(2)内核timer_list 使用举例
内核timer_list 基于jiffies时钟滴答使用检测看门狗举例
#include <linux/timer.h>
static struct timer_list wdt_timer;
void wdt_callback(struct timer_list *t) {
if(!feed_dog()) { // 检测喂狗信号
panic("Watchdog timeout!");
}
mod_timer(&wdt_timer, jiffies + msecs_to_jiffies(500)); // 500ms周期检测
}
void init_watchdog(void) {
timer_setup(&wdt_timer, wdt_callback, 0);
mod_timer(&wdt_timer, jiffies + msecs_to_jiffies(500));
}
Linux内核中使用timer_stats统计定时器事件
#include <linux/module.h>
#include <linux/timer.h>
#include <linux/proc_fs.h>
static struct timer_list test_timer;
static unsigned long timeout_count;
void timer_callback(struct timer_list *t) {
timeout_count++;
mod_timer(&test_timer, jiffies + msecs_to_jiffies(100));
}
static int proc_show(struct seq_file *m, void *v) {
seq_printf(m, "Timer stats:\n");
seq_printf(m, "Expired count: %lu\n", timeout_count);
seq_printf(m, "Current jiffies: %lu\n", jiffies);
return 0;
}
static int proc_open(struct inode *inode, struct file *file) {
return single_open(file, proc_show, NULL);
}
static const struct proc_ops proc_fops = {
.proc_open = proc_open,
.proc_read = seq_read,
.proc_lseek = seq_lseek,
.proc_release = single_release,
};
static int __init timer_init(void) {
timer_setup(&test_timer, timer_callback, 0);
mod_timer(&test_timer, jiffies + msecs_to_jiffies(100));
proc_create("timer_stats", 0, NULL, &proc_fops);
return 0;
}
static void __exit timer_exit(void) {
del_timer_sync(&test_timer);
remove_proc_entry("timer_stats", NULL);
}
module_init(timer_init);
module_exit(timer_exit);
MODULE_LICENSE("GPL");