c - 为什么 nanosleep() 会增加一个恒定的延迟,我该如何避免呢?

标签 c raspberry-pi real-time

我想用我的 RaspberryPi 3 驱动步进电机。我需要每秒生成大约 10000 个脉冲,这意味着我需要以大约 100us 的间隔生成脉冲。我知道 Raspberry 可以生成 PWM,但事实并非如此,因为我需要精确控制脉冲数以及加速/减速,所以我更喜欢显式循环。

虽然忙循环提供了相当精确的计时,但它显然会消耗 100% 的 CPU 时间。同时 nanosleep() 在时间精度和 CPU 负载之间提供了很好的平衡——我可以用大约 10% 的 CPU 负载来驱动电机。

但是。我写了一小段代码来测量 nanosleep() 延迟

    unsigned long iterations = 5000;
    for(int d=10; d<500; d+=5)
    {
        unsigned long accumDelayTime = 0;
        unsigned long accumExpDelayTime = 0;
        for(unsigned long i=0; i<iterations; i++)
        {
            accumExpDelayTime += d;

            unsigned long start = micros();
            struct timespec ts;
            ts.tv_sec = 0;
            ts.tv_nsec = 1000*d;
            clock_nanosleep(CLOCK_REALTIME, 0, &ts, NULL);

            unsigned long end = micros();

            accumDelayTime += end - start;
        }

        printf("%d\t%d\t%d\n", accumExpDelayTime / iterations, accumDelayTime / iterations, (accumDelayTime - accumExpDelayTime) / iterations);
    }

我完全理解通用 linux(尤其是 Raspbian)不是 RTOS,还有其他进程与我的程序共享相同的 CPU 资源 - 我对此非常满意。如果有其他 CPU 消耗进程,我的应用程序是否会变慢一点我没问题。

但结果非常令人惊讶。列为:请求延迟、实际延迟、请求延迟与实际延迟之间的差异

10      80      70
15      85      70
20      89      69
25      95      70
30      99      69
35      105     70
40      110     70
45      114     69
50      123     70
55      124     69
60      129     69
65      134     69
70      130     60    <---- here I run CPU-heavy process
75      135     60
80      140     60
85      145     60
90      150     60
95      158     62
100     161     61
105     166     61
110     172     62
115     177     62
120     181     61
125     186     61
130     191     61
135     205     70    <---- here it finished
140     210     70
145     215     70
150     220     70
155     225     70
160     230     70
165     235     70

我尝试了 nanosleep()、clock_nanosleep() 和 usleep() - 结果几乎相同。

我对这些结果几乎没有疑问: 1) 为什么我的期望 sleep 时间与实际 sleep 时间不同? 2) 这种差异非常稳定,不依赖于请求的延迟。有人对此有解释吗? 3) 如果 CPU 负载增加,为什么这种差异会变小(我预计恰恰相反)?

最佳答案

您的进程正在从用户空间运行。为了既能 sleep 又能得到时间,你需要切换到内核空间。这会产生开销。此外,任何 sleep 功能都只能保证在 sleep 定时器到期后的某个时间唤醒。

最重要的是,为了尝试获得所需的精度,您可能需要将代码编写为设备驱动程序。这使您可以直接访问所需的高分辨率计时器。

关于c - 为什么 nanosleep() 会增加一个恒定的延迟,我该如何避免呢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54620641/

相关文章:

c - 如何将字符串插入缓冲区?

c++ - 我可以确定参数是否是字符串文字吗?

c - malloc 是否递归工作?

matlab - 阅读未压缩的yuv视频文件的帧?

linux - 在运行 raspbian 的树莓派 3 上定期运行 shell 脚本

Firebase 规则通配符和子项比较

c - 文字字符串和函数返回值是左值还是右值?

java - 树莓派上的数据库

garbage-collection - Lua 的 GC 和实时游戏

android - Android 上持久移动连接的最佳实践?