0

最近我一直在尝试使用挂钟作为参考创建一个等待 25 毫秒的等待函数。我环顾四周,发现“gettimeofday”,但我一直遇到问题。我的代码(简化):

while(1)
{
    timeval start, end;
    double t_us;
    bool release = false;    
    while (release == false)
    {
        gettimeofday(&start, NULL);

        DoStuff();

        {
            gettimeofday(&end, NULL);
            t_us = ( (end.tv_sec - start.tv_sec) * 1000*1000) + (end.tv_usec - start.tv_usec);

            if (t_us >= 25000) //25 ms
            {
                release = true;
            }
        }
    }
}

此代码在线程 (Posix) 中运行,并且就其本身而言,工作正常。DoStuff() 每 25 毫秒调用一次。但是,如果可以(如您所料),它确实会吃掉所有的 CPU,所以显然这不是一个好主意。

当我尝试通过添加 Sleep(1) 来限制它时;在 if 语句之后的等待循环中,整个事情减慢了大约 50%(也就是说,它每 37 毫秒左右调用一次 DoStuff。这对我来说毫无意义 - 假设 DoStuff 和任何其他线程在 (25 - 1) ms DoStuff 的调用率不应受到影响(允许 1ms 误差范围)

我还尝试了 Sleep(0)、usleep(1000) 和 usleep(0),但行为是相同的。

每当另一个更高优先级的线程需要 CPU 时间(没有睡眠)时,都会发生相同的行为。就好像当线程重新启动运行时时钟停止计数一样。

我知道 gettimeofday 容易受到 NTP 更新等的影响...所以我尝试使用 clock_gettime 但在我的系统上链接 -ltr 会导致问题,所以我认为这不是一个选项。

有谁知道我做错了什么?

4

2 回答 2

2

这里缺少的部分是内核如何基于时间片进行线程调度。在粗略的数字中,如果您在时间片开始时休眠 1 毫秒并且调度以 35 毫秒的时钟速率完成,那么您的线程可能不会在 35 毫秒内再次执行。如果你休眠 40 毫秒,你的线程可能在 70 毫秒内不会再次执行。如果不更改调度,您无法真正更改它,但由于系统的整体性能影响,不建议这样做。您可以使用“高分辨率”计时器,但通常这是在“还没有到时候,咀嚼 CPU”的紧密循环浪费循环中实现的,所以这也不是真正可取的。

如果您使用高分辨率时钟并在 DoStuff 循环中频繁查询它,您可能会玩一些技巧,例如运行 30 毫秒,然后执行 sleep(1),这可以有效地在剩余时间片内放弃您的线程(例如5ms) 让其他线程运行。如果你愿意的话,一种合作/先发制人的多任务处理。不过,您仍然有可能在很长一段时间内无法恢复工作...

于 2012-10-17T13:11:45.670 回答
1

sleep()/usleep() 的所有变体都涉及将 CPU 让给其他可运行任务。然后,您的程序只能在内核重新调度后才能运行,在您的情况下,这似乎持续约 37 毫秒。

于 2012-10-17T11:56:11.310 回答