【问题标题】:How to sleep for a few microseconds如何睡几微秒
【发布时间】:2011-06-26 14:06:20
【问题描述】:

考虑以下代码:

#include <stdio.h>
#include <time.h>
#include <math.h>

// Compile with gcc -lrt -lm -o test_clock test_clock.c

#define CLOCK CLOCK_MONOTONIC

int main(int argc, char** argv) {
    double temp, elapsed;
    int j;
    struct timespec requestStart, requestEnd, req;

    // Pseudo-sleep
    clock_gettime(CLOCK, &requestStart);
    temp = 0;
    for(j=0; j < 40; j++)
        temp += sin(j);
    clock_gettime(CLOCK, &requestEnd);
    elapsed = ( requestEnd.tv_sec - requestStart.tv_sec ) / 1e-6
                 + ( requestEnd.tv_nsec - requestStart.tv_nsec ) / 1e3;
    printf("Elapsed: %lf us\n", elapsed);

    // Nanosleep
    clock_gettime(CLOCK, &requestStart);
    req.tv_nsec = 5000;
    req.tv_sec = 0;
    clock_nanosleep(CLOCK, 0, &req, NULL);
    clock_gettime(CLOCK, &requestEnd);
    elapsed = ( requestEnd.tv_sec - requestStart.tv_sec ) / 1e-6
                 + ( requestEnd.tv_nsec - requestStart.tv_nsec ) / 1e3;

    printf("Elapsed: %lf us\n", elapsed);

}

在我的 2.6.32 系统上,结果是

Elapsed: 5.308000 us
Elapsed: 69.142000 us

我同意这很可能是因为 nanosleep() 要求内核重新安排进程。我怎样才能避免这种情况?我想保留 CPU 的所有权,并且只是闲置一段精确的时间。

【问题讨论】:

  • 你有 linux 和 real-time 作为标签。为什么?它们是粉笔和奶酪。
  • @David:好像没有疯狂的人在 linux-rt 或类似的东西上工作……哦等等。
  • 我很好奇:具体的上下文是什么?你需要这种准确度是为了什么?
  • @asdf:磁约束等离子体的实时反馈控制。

标签: c linux real-time glibc libc


【解决方案1】:

如果您希望您的应用程序能够尽可能精确地“休眠”,请首先将您的应用程序置于实时条件下

  • 为您的程序/线程使用实时调度程序类:SCHED_FIFO 或 SCHED_RR
  • 提升您的程序/线程优先级
  • 如果您要“睡眠”的时间少于内核将要处理的最小时间,请手动忙等待

看看http://www.drdobbs.com/184402031

还有这个问题:nanosleep high cpu usage?

【讨论】:

  • 有了实时优先级,nanosleep 可以按照我想要的方式工作。谢谢!
  • SCHED_DEADLINE 来了! lwn.net/Articles/356576 lwn.net/Articles/396634 希望能提高 Linux 上的 RT 可用性。 (如果不小心SCHED_FIFO/SCHED_RR,很容易锁死整机。)
【解决方案2】:

OS 调度程序不会执行诸如“哦,将这个线程从处理器中取出正好 86 个时钟周期然后重新打开”之类的事情。

你放弃了处理器,你已经放弃了处理器。操作系统会在您愿意时让您重新开机。很有可能你必须等到其他正在运行的东西放弃了处理器,然后才能偷偷溜回来。

【讨论】:

  • 另外,取决于芯片组、cpu 和其他一些东西,clock_gettime() 可能既昂贵又不确定。即使第一种方法表明问题是线程被抢占而不是时钟实现,也很难指出这里最大的问题是什么。
  • 好吧,您将立即使用sched_setscheduler(SCHED_FIFO)(或SCHED_RRSCHED_DEADLINE,如果可用)重新安排。但这些都是非常特殊的情况。
  • 我不想占用处理器的线程,我只想在一段精确的时间内什么都不做。有没有办法做到这一点?
  • @Nikratio:如果你需要在某个时间精确执行,你基本上需要一个实时操作系统。否则,您无法保证在任何给定点都不会更换处理器。为什么这个时候需要精准跑呢?
  • @bestsss:这绝对是一个多任务系统。也许您应该阅读有关阿波罗 11 号着陆的说明,其中一个软件组件(着陆雷达)无法跟上并按时完成,但系统能够使所有其他具有实时要求的组件顺利运行。
【解决方案3】:

好吧,你必须学会​​忍受它,因为手册页指出,部分是:the actual time slept may be longer, due to system latencies and possible limitations in the timer resolution of the hardware :-)

现在关于您问题的答案,我最好的猜测是,这是因为您的第一个循环正在进程中运行。换句话说,没有涉及上下文切换,因为您完全运行 CPU,并且您将在调度程序提供给您的 100 毫秒范围内完成所有工作。

但是,nanosleep 很有可能会将您转出,因为您明确要求让您进入睡眠状态。在持续时间结束之前,将您的流程置于紧密的while 循环中不会如此低效:-)

这意味着您会受到调度程序的所有变幻莫测包括另一个进程可能完全用完其量子的事实,因此您的进程可能至少在 100 毫秒内离开那里。在负载足够重的系统上,它可能会出现一段时间。

【讨论】:

    【解决方案4】:
    // busy wait for 10 microseconds
    struct timespec ttime,curtime;
    
    // get the time
    clock_gettime(CLOCK_REALTIME,&ttime);
    
    // clear the nanoseconds and keep the seconds in order not to overflow the nanoseconds
    ttime.tv_nsec = 0;
    
    // set it back
    clock_settime(CLOCK_REALTIME,&ttime);
    
    // get the time again 
    clock_gettime(CLOCK_REALTIME,&ttime);
    
    // increase the nano seconds by 10*1000
    ttime.tv_nsec += 10000;
    
    // loop
    while(true){
      clock_gettime(CLOCK_REALTIME,&curtime);
      if (curtime.tv_nsec > ttime.tv_nsec)
        break;
    }
    

    // 比睡着好多了。

    【讨论】:

      【解决方案5】:

      您可以使用usleep 方法以微秒为单位进行睡眠。

      【讨论】:

      • 这与clock_nanosleep 几乎相同,正如问题和其他回复中所解释的那样,它并不能完全发挥作用。
      【解决方案6】:

      效率 - 允许以几个时钟周期的精度切换任务的操作系统将几乎没有其他作用。

      有专门的操作系统可以执行此操作 - 但在常规硬件上,您需要为管理程序支付大量开销

      【讨论】:

        【解决方案7】:

        这是一个保留的答案 - 我不知道相关的 linux 内部原理,希望专家能来解决它​​。

        一种可能性是 69us 只是取消调度然后重新调度线程的原始开销。即使睡眠时间很短,内核也可能会做很多工作来执行上下文切换(或半个上下文切换,如果没有要安排的内容),然后几乎立即撤消它。我不知道在典型 PC 上的 linux 上“应该”需要多长时间。

        如果这不能解释它,调度程序通常有一个“时间片”的概念,即在调度程序考虑切换之前,调度线程将运行多长时间,除非它自行取消调度或其他具有更高优先级的东西变得可调度。内核将有低级计时器在时间片结束时触发中断(除了为某些其他事件触发的中断,例如可以解除线程阻塞的 I/O)。当时间片结束时,调度程序可以决定是继续使用同一个线程,还是切换到另一个线程。

        所以看起来好像当你睡觉时,(a) 调度程序实际上并没有设置一个计时器来让你的线程在请求​​的时间可以调度,它只是在等待一个时间片,所以 CPU 处于空闲状态超过必要的时间;或者(b)它使您的线程在请求​​的时间可调度,但是当您通过睡眠放弃执行时,其他具有相同优先级的线程进入,并且调度程序没有理由更喜欢您,直到轮到您了" 再次根据调度程序通常用来决定调度哪个线程的任何规则。

        不过,69us 很短,不能成为时间切片的产物。

        您似乎有一个基本的解决方案 - 您可以通过坐在循环中检查时间来延迟很短的时间,就像自旋锁一样。但是,正如其他人所说,在非实时系统中,根据定义或多或少,您不能要求调度程序在任何特定时间运行您的线程。即使在实时系统中,如果您与同等优先级的线程竞争,您可能会输,而如果您与更高优先级的线程竞争,您输。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-11-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-10-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多