Linux下C语言无信号回调、无需FD/poll的周期定时器实现问询
C语言无信号/无文件描述符周期定时器实现
实现思路
采用独立工作线程+高精度睡眠的方案,完全规避信号机制与文件描述符监听逻辑,定时器到期后直接在工作线程上下文调用回调函数,不存在信号来源冲突的问题。
方案特点
- 无信号依赖,无需处理信号来源区分逻辑
- 不涉及任何文件描述符、poll/epoll等IO多路复用逻辑
- 支持自定义触发间隔、自定义回调参数
- 支持手动启停控制
完整代码示例
#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <time.h> #include <unistd.h> #include <errno.h> // 定时器结构体定义 typedef struct { unsigned int interval_sec; // 触发间隔,单位:秒 void (*callback)(void*); // 到期回调函数指针 void *callback_arg; // 回调函数入参 volatile int is_running; // 运行状态标记,volatile避免编译器优化 pthread_t thread_id; // 定时器工作线程ID } periodic_timer_t; // 定时器工作线程入口 static void* timer_thread(void *arg) { periodic_timer_t *timer = (periodic_timer_t*)arg; struct timespec sleep_time = { .tv_sec = timer->interval_sec, .tv_nsec = 0 }; while (timer->is_running) { // 高精度睡眠,被信号中断时自动续睡剩余时间 int ret = nanosleep(&sleep_time, &sleep_time); if (ret == -1 && errno != EINTR) { perror("nanosleep执行失败"); break; } // 睡眠结束后二次校验运行状态,避免停止后误触发回调 if (timer->is_running && timer->callback) { timer->callback(timer->callback_arg); } // 重置睡眠时间为完整周期 sleep_time.tv_sec = timer->interval_sec; sleep_time.tv_nsec = 0; } return NULL; } /** * @brief 启动周期定时器 * @param timer 定时器实例指针 * @return 0启动成功,-1启动失败 */ int timer_start(periodic_timer_t *timer) { if (!timer || timer->interval_sec == 0 || !timer->callback) { return -1; } timer->is_running = 1; int ret = pthread_create(&timer->thread_id, NULL, timer_thread, timer); if (ret != 0) { timer->is_running = 0; perror("工作线程创建失败"); return -1; } return 0; } /** * @brief 停止周期定时器 * @param timer 定时器实例指针 */ void timer_stop(periodic_timer_t *timer) { if (!timer || !timer->is_running) { return; } timer->is_running = 0; pthread_join(timer->thread_id, NULL); } // ---------------------- 示例代码 ---------------------- void demo_callback(void *arg) { const char *msg = (const char*)arg; time_t now = time(NULL); printf("[%s] 定时器触发,回调参数:%s\n", ctime(&now), msg); } int main() { periodic_timer_t timer = { .interval_sec = 2, // 每2秒触发一次 .callback = demo_callback, .callback_arg = "测试定时器" }; printf("启动定时器,10秒后自动停止...\n"); timer_start(&timer); // 主线程模拟业务运行 sleep(10); timer_stop(&timer); printf("定时器已停止\n"); return 0; }
编译运行说明
编译时需要链接pthread线程库,命令如下:gcc timer_demo.c -o timer_demo -lpthread
注意事项
- 回调函数的执行耗时会占用定时器间隔,若回调执行需要1秒、间隔设置为2秒时,实际两次触发间隔会变为3秒。如果需要严格保证间隔精度,建议回调内仅做轻量操作,重逻辑异步抛给其他业务线程处理。
is_running用volatile修饰是为了避免编译器优化读取缓存,保证多线程下状态修改的可见性,若存在多个线程并发操作定时器的场景,建议对状态变量加互斥锁保护。- 如果需要支持小于1秒的触发间隔,可修改
interval_sec为带纳秒的结构体,调整nanosleep的配置即可。
内容的提问来源于stack exchange,提问作者Jimmy
相关产品推荐
相关产品推荐

