请考虑以下代码:
#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的所有权,并且在一段精确的时间内闲置。
答案 0 :(得分:8)
如果您希望应用程序能够尽可能精确地“睡眠”,请首先将您的应用程序置于实时状态
查看http://www.drdobbs.com/184402031
另外一个问题:nanosleep high cpu usage?
答案 1 :(得分:7)
操作系统调度程序不会执行任何操作,例如“哦,将此线程从处理器中取出正好86个时钟周期然后重新启用”。
你放弃了处理器,你放弃了处理器。操作系统会让你重新回到它的感觉。您可能需要等到运行的其他任何东西放弃处理器才能重新开始。
答案 2 :(得分:2)
好吧,你必须学会使用它,因为手册页说明了部分:the actual time slept may be longer, due to system latencies and possible limitations in the timer resolution of the hardware
: - )
现在关于你的问题的回答,我最好的猜测是因为你的第一个循环是在进程中运行的。换句话说,没有涉及上下文切换,因为您正在运行CPU,并且您将在调度程序为您提供的100ms量程内完成所有工作。
然而,由于您明确要求进入睡眠状态,nanosleep
很可能会将您转出。在持续时间结束之前将流程置于紧密的while
循环中,效率不会太低: - )
这意味着您受到调度程序的所有变幻莫测的影响,包括另一个进程可能完全耗尽其量子的事实,因此您的进程可能至少在100ms之外。在一个负载很重的系统上,它可能已经存在了很长一段时间。
答案 3 :(得分:2)
// 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要好得多。
答案 4 :(得分:1)
您可以使用usleep
方法以微秒为单位获得睡眠。
答案 5 :(得分:0)
效率 - 允许以几个时钟周期的精度切换和切换任务的Os将会做很少的事情。
有专门的操作系统可以执行此操作 - 但在常规硬件上,您需要为虚拟机管理程序支付大量开销
答案 6 :(得分:0)
这是一个持久的答案 - 我不知道相关的linux内部,希望专家可以来并清理它。
一种可能性是69us只是解决问题的原始开销,然后重新安排线程。即使睡眠很短,内核可能会做很多工作来执行上下文切换(或半个上下文切换,如果没有什么可以安排),然后几乎立即撤消它。我不知道在典型的PC上“应该”花多长时间。
如果这不能解释它,调度程序通常具有“时间片”的概念,即在调度程序考虑切换它之前调度线程将保持运行多长时间,除非它自行计划或其他具有较高优先级的东西变得可调度。内核将在时间片结束时触发中断的低级定时器(除了为某些其他事件(例如可以解除阻塞线程的I / O)触发的中断)。当时间片结束时,调度程序可以决定是继续使用相同的线程,还是切换到另一个线程。
所以看起来好像在你睡觉时,(a)调度程序实际上并没有设置一个定时器,它会使你的线程在请求的时间内可调度,它只是在等待一个时间片,所以CPU正在空闲超过必要的;或者(b)它使你的线程在所要求的时间内可以调度,但当你通过睡眠放弃执行时,其他一些具有相同优先级的线程进入,并且调度程序没有理由更喜欢你,直到它“轮流” “再次根据调度程序通常用来决定要调度的线程的任何规则。
但是,69us很难成为一个时空的人工制品。你似乎有一个基本的解决方案 - 你可以通过坐在循环中检查时间来延迟很短的时间,就像一个螺旋锁。然而,正如其他人所说的那样,在非实时系统中,或多或少根据定义,您无法要求调度程序在任何特定时间运行您的线程。即使在实时系统中,如果您正在与同等优先级的线程竞争,您可能会失败,如果您与优先级较高的线程竞争,将输掉。