You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 12:39:04