如何睡几个微秒

考虑下面的代码:

#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的所有权,只是闲置一段时间。

Solutions Collecting From Web of "如何睡几个微秒"

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

  • 为您的程序/线程使用实时调度程序类:SCHED_FIFO或SCHED_RR
  • 提升你的程序/线程优先级
  • 如果你要“睡眠”的内核要处理的最小量,手动busywait

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

而另一个问题: nanosleep高CPU使用率?

操作系统调度程序不会做任何事情,“哦,把这个线程关闭处理器正好86个时钟周期,然后把它放回去”。

你放弃处理器,你放弃了处理器。 操作系统将会让你感觉到它。 有机会,你将不得不等待,直到其他任何正在运行放弃处理器之前,你可以偷偷回来。

那么,自从手册页指出,你必须学会​​忍受它,部分the actual time slept may be longer, due to system latencies and possible limitations in the timer resolution of the hardware 🙂

现在至于你的问题的答案 ,我最好的猜测是,这是因为你的第一个循环正在运行。 换句话说,没有上下文切换,因为你正在运行CPU,你将在调度器给你的100ms量子内完成所有工作。

但是,由于您明确要求入睡,所以睡眠很可能会将您关闭。 它将不会太低效,只是把你的进程放在一个紧凑的while循环中,直到持续时间结束:-)

这意味着你会受到调度程序中所有的变幻莫测的影响, 包括另一个进程可能完全使用它的量子,因此你的进程至少可能超过100ms。 在负载很重的系统上,可能会出现相当长的一段时间。

 // 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; } 

//比睡觉好多了

你可以使用usleep方法以微秒单位获得睡眠。

效率 – 允许以几个时钟周期的精度切换任务的Os将不会做任何其他事情。

有专门的操作系统可以做到这一点 – 但是在常规的硬件上,为虚拟机管理程序付出了很大的开销

这是一个控制的答案 – 我不知道相关的linux内部,希望专家能够来清理它。

一种可能性就是69us仅仅是重新调度线程的原始开销,然后重新调度线程。 即使睡眠很短,内核可能会执行很多工作来执行上下文切换(或者如果没有任何计划,则切换一半上下文),然后几乎立即撤消它。 我不知道在典型的PC上“应该”在Linux上运行多长时间。

如果这不能解释它,一个调度程序通常有一个“时间片”的概念,这是一个预定的线程将在调度程序考虑切换之前运行多长时间,除非它要么去除本身,要么去除更高的优先级变得可调度。 内核将有低级别的定时器在时间片结束时触发中断(除了针对某些其他事件(例如可以解锁线程的I / O)触发的中断外)。 当时间片结束时,调度器可以决定是继续使用同一个线程还是切换到另一个线程。

所以看起来好像在睡觉的时候,(a)调度程序实际上并没有设置一个定时器,它可以让你的线程在请求​​的时间内调度,只是等待一个时间片,所以CPU空闲时间超过了必要的时间; 否则(b)它会在请求的时间调度你的线程,但是当你通过睡眠放弃执行时,一些其他的同等优先级的线程进入了,调度程序没有理由让你越过它,直到它“轮到你了“再次根据调度程序通常用来决定要调度的线程的任何规则。

尽管如此,69us还是很短的时间。

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