文章目录
0. 概要
在 QNX 系统上,usleep
的精度较低,特别是在 1ms 以下的延时。对于 10ms 以上的延时,误差较小。
1. 测试代码
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
double usleep_real_cost(unsigned int us) {
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
usleep(us);
clock_gettime(CLOCK_MONOTONIC, &end);
unsigned int cost = (end.tv_sec - start.tv_sec) * 1e9 + (end.tv_nsec - start.tv_nsec);
return cost;
}
int main() {
const unsigned int us_list[] = {1, 10, 100, 1000, 10000, 100000, 1000000};
for (int i = 0; i < sizeof(us_list) / sizeof(unsigned int); i++) {
unsigned int us = us_list[i];
double cost = usleep_real_cost(us);
printf("usleep %dus cost %fms\n", us, cost / 1e6);
}
}
2. 测试结果
2.1 在 QNX lidar 上测试结果:
# ./testsleep_qnx
usleep 1us cost 2.000000ms
usleep 10us cost 2.000000ms
usleep 100us cost 2.000000ms
usleep 1000us cost 2.000000ms
usleep 10000us cost 11.000000ms
usleep 100000us cost 101.000000ms
usleep 1000000us cost 1001.000000ms
2.2 在 QNX VMware 虚拟机中测试结果:
# ./testsleep_qnx
usleep 1us cost 2.000000ms
usleep 10us cost 2.000000ms
usleep 100us cost 2.000000ms
usleep 1000us cost 2.000000ms
usleep 10000us cost 11.000000ms
usleep 100000us cost 101.000000ms
usleep 1000000us cost 1001.000000ms
2.3 在 Ubuntu 上测试结果:
./testsleep_ubuntu
usleep 1us cost 0.480022ms
usleep 10us cost 0.418154ms
usleep 100us cost 0.495366ms
usleep 1000us cost 1.097107ms
usleep 10000us cost 10.065300ms
usleep 100000us cost 100.435447ms
usleep 1000000us cost 1000.077292ms
3. 问题分析
3.1 QNX的调度精度和时钟分辨率
QNX 的 usleep
精度受限于系统调度和时钟分辨率,特别是在小于 1ms 的延时时,误差较大。测试结果显示,QNX 在 1us 和 10us 的延时测试中误差为 2ms,这表明系统时钟分辨率限制了其精度。
3.2 虚拟化环境的影响
虚拟化环境对 usleep
精度影响较小,但虚拟机调度延迟可能导致延时误差。问题主要还是由于操作系统的调度和硬件时钟分辨率。
3.3 nanosleep()
vs usleep()
QNX 社区建议使用 nanosleep()
来代替 usleep()
,因为它允许指定更高精度的时间间隔,并可以选择使用 CLOCK_MONOTONIC
时钟,避免系统时间调整对延时的影响。
示例代码:
struct timespec req = {0, us * 1000}; // us -> 纳秒
nanosleep(&req, NULL);
nanosleep()
使用 CLOCK_MONOTONIC
时钟,避免了系统时间(CLOCK_REALTIME
)的调整对延时的影响。
3.4 usleep()
精度和操作系统调度
usleep()
精度受操作系统调度器的影响。在实时操作系统中,精度应较高,但仍受限于硬件时钟和调度策略。对于更精确的延时,使用 nanosleep()
会更合适。