2025年07月13日/ 浏览 9
在C语言中实现定时器功能,通常需要借助操作系统提供的信号机制。UNIX系统通过SIGALRM
信号实现定时中断,配合setitimer()
系统调用,可以创建精确的定时触发机制。其核心原理如下图所示:
c
[信号产生] → [内核调度] → [用户态处理] → [回调执行]
当定时器到期时,内核会向进程发送信号,触发预先注册的信号处理函数。这种机制虽然简单,但在实现时需要注意信号安全函数和异步处理带来的复杂性。
使用setitimer()
设置定时间隔,需包含sys/time.h
头文件:
c
void inittimer(int microseconds) {
struct itimerval timer = {
.itinterval = { .tvsec = 0, .tvusec = microseconds },
.itvalue = { .tvsec = 0, .tvusec = microseconds }
};
setitimer(ITIMERREAL, &timer, NULL);
}
通过sigaction()
注册信号处理函数,比传统的signal()
更安全:
c
void registerhandler(void (*handler)(int)) {
struct sigaction sa = {
.sahandler = handler,
.saflags = SARESTART
};
sigemptyset(&sa.sa_mask);
sigaction(SIGALRM, &sa, NULL);
}
回调函数需遵守信号安全规范(避免使用printf
等非重入函数):
c
volatile sigatomict timer_flag = 0;
void timercallback(int sig) {
timerflag = 1; // 设置标志位
// 实际业务逻辑建议通过标志位触发
}
以下是一个毫秒级精度的定时器实现:
c
typedef void (*timer_cb)(void);
static timercb usercallback;
void signalhandler(int sig) {
if (usercallback) user_callback();
}
void settimer(int ms, timercb cb) {
user_callback = cb;
struct sigaction sa = {
.sa_handler = signal_handler,
.sa_flags = SA_RESTART
};
sigaction(SIGALRM, &sa, NULL);
struct itimerval timer = {
.it_interval = { .tv_sec = ms/1000, .tv_usec = (ms%1000)*1000 },
.it_value = { .tv_sec = ms/1000, .tv_usec = (ms%1000)*1000 }
};
setitimer(ITIMER_REAL, &timer, NULL);
}
// 使用示例
void heartbeat() {
static int count = 0;
printf(“Tick %d\n”, ++count); // 实际项目中应替换为信号安全输出
}
int main() {
set_timer(500, heartbeat); // 500ms触发一次
while(1) pause(); // 主线程阻塞等待信号
return 0;
}
timer_gettime()
检查实际间隔pthread_sigmask
控制信号处理线程timer_create
)