linux 内核态和用户态定时器函数使用总结
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 5void 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 // 采集间隔200msint 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");