求助:60Hz定时器在Windows正常但Linux下失效问题(附代码)
嘿,我帮你排查出问题所在了,咱们一步步拆解:
问题出在哪?
你现在用的clock()函数根本不是用来测真实时间的!它统计的是你的进程实际占用的CPU时间,不是墙上流逝的真实时间:
- Windows下你的程序是死循环忙等,CPU几乎被占满,所以CPU时间和真实时间几乎同步,定时器看起来能按60Hz跑。
- 但Linux下系统调度器会把CPU分给其他进程,或者你的程序没拿到实时调度权限,导致CPU时间的增长比真实时间慢。比如真实时间过了32ms,你的进程才攒够16ms的CPU时间,这时候定时器才触发,实际间隔就变成了32ms,60次下来就是差不多2秒,正好和你看到的输出对上。
另外你的定时器逻辑还有个小bug:触发时你用pre += diff更新时间,而不是pre += 16*PRE_MS。这会让每次的延迟都累积下来,哪怕CPU时间和真实时间同步,长期下来定时器也会越来越不准。
怎么改?
要做跨平台的高精度定时器,得用专门测真实时间的函数,别再用clock()了。给你写了个兼容Windows和Linux的版本:
#include <stdio.h> #include <time.h> // 跨平台获取当前毫秒级真实时间 long long get_current_ms() { #ifdef _WIN32 // Windows用GetTickCount64,需要链接kernel32库 return (long long)GetTickCount64(); #else // Linux用单调时钟,不受系统时间调整影响 struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return (long long)ts.tv_sec * 1000 + ts.tv_nsec / 1000000; #endif } int main() { long long pre = get_current_ms(); int cnt = 0; // 60Hz对应约16.6ms,这里用16ms或者调整成17ms都可以,看你需求 const long long interval_ms = 16; while (1) { long long now = get_current_ms(); long long diff = now - pre; if (diff >= interval_ms) { cnt++; if (cnt >= 60) { printf("%lld\n", pre); cnt = 0; } // 重点:更新为下一次预期触发时间,避免延迟累积 pre += interval_ms; // 如果系统卡顿太久,直接跳到当前时间,避免一次性触发N次 if (pre < now) { pre = now; } } } }
编译注意事项
- Windows(MinGW GCC):编译时要链接kernel32库,命令:
gcc timer.c -o timer.exe -lkernel32 - Linux:有些版本需要链接rt库,命令:
gcc timer.c -o timer -lrt(新版GCC可能不用,但加上更稳妥)
额外小贴士
- 用
CLOCK_MONOTONIC而不是系统时间,因为系统时间可能被手动修改或者NTP同步跳变,单调时钟只会一直递增,适合做定时器。 - 如果要严格卡60Hz,可以把间隔改成16667微秒(也就是16.667ms),用微秒级计算会更精准。
- 死循环会占100%CPU,要是想降低占用,可以在循环里加个短暂休眠,比如Linux下
usleep(1000),Windows下Sleep(1),这样CPU占用会降下来,精度也够60Hz用。
内容的提问来源于stack exchange,提问作者叶ch
相关产品推荐
相关产品推荐

