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

POSIX定时器实现20ms周期线程实测时长偏短,是什么原因?

误差成因

  • 计时逻辑错误
    你当前的测量区间是「本次业务逻辑启动时间」到「本次wait_period返回时间」,这个值本质是「业务执行耗时 + 等待定时器触发的耗时」,本就不等于你设置的20ms周期。正确的周期测量应该是两次业务逻辑启动的时间差(即两次start变量采样的间隔),这个值才是你实际的任务调度周期。
  • 定时器启动时机提前
    你在make_periodic函数末尾调用timer_settime时,定时器就已经开始计时,而不是在第一次业务执行完成后才启动。调用make_periodic后,你还需要执行线程初始化printf、进入循环、采样start、执行业务逻辑,这一系列操作已经消耗了几百微秒不等的时间,等到你调用wait_period时,定时器已经走完了一小段,最终等待时长自然小于20ms,叠加后你的测量值就会稳定略小于20ms。
  • IO操作的耗时波动
    你在线程中混用了printf和std::cout两种IO操作,这类操作有内核缓冲、调度开销,本身耗时会有微秒级的波动,也会贡献小范围的测量误差。

现有实现的问题

  • 基于POSIX信号的周期实现本身有额外开销:信号的触发、sigwait的唤醒都有内核态到用户态的切换开销,优先级不高的线程还可能出现调度延迟,导致周期变长。
  • 定时器创建后没有和任务执行的节奏对齐,第一次周期就存在固有偏差,长期运行下这个偏差不会累积,但首次调度的偏移是固定存在的。

优化建议

你可以改用clock_nanosleep的绝对时间模式实现周期线程,不需要依赖信号,逻辑更简单,精度更高:

static void *thread_1(void *arg)
{
    const long period_ns = 20 * 1000 * 1000; // 20ms转纳秒
    struct timespec next;
    // 以当前时间为基准初始化下次唤醒时间
    clock_gettime(CLOCK_MONOTONIC, &next);

    while (1) {
        auto start = std::chrono::high_resolution_clock::now();
        // 你的业务逻辑
        printf("Hello\n");
        thread_1_count++;
        // 计算下一次唤醒的绝对时间
        next.tv_nsec += period_ns;
        if (next.tv_nsec >= 1000000000) {
            next.tv_sec += 1;
            next.tv_nsec -= 1000000000;
        }
        // 休眠到指定绝对时间,即使被信号中断也会自动重试
        clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next, NULL);
    }
    return NULL;
}

内容的提问来源于stack exchange,提问作者Digget

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 05:15:01