问题
Consider the following code:
#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);
}
On my 2.6.32 system, the result is
Elapsed: 5.308000 us
Elapsed: 69.142000 us
I agree that this is most likely because nanosleep() asks the kernel to reschedule the process. How can I avoid this? I want to keep ownership of the CPU and just idle around for a precise amount of time.
回答1:
If you want your application to be able to "sleep" as precisely as possible, first put your application in realtime conditions
- use a realtime scheduler class for your program / thread : SCHED_FIFO or SCHED_RR
- elevate your program / thread priority
- and if you're going to "sleep" for less than the minimum amount the kernel is going to handle, manually busywait
Have a look at http://www.drdobbs.com/184402031
And this other question: nanosleep high cpu usage?
回答2:
The OS scheduler is not going to do anything like "oh, take this thread off the processor for exactly 86 clock cycles then put it back on".
You give up the processor, you've given up the processor. The OS will put you back on when it feels like it. Chances are you'll have to wait until whatever else is running gives up the processor before you can sneak back on.
回答3:
Well, you'll have to learn to live with it since the man page states, in part: the actual time slept may be longer, due to system latencies and possible limitations in the timer resolution of the hardware
:-)
Now as to the answer to your question, my best guess is that it's because your first loop is running in-process. In other words, there are no context switches involved since you're running the CPU flat out and you will be doing all that work within your 100ms quanta given to you by the scheduler.
However, there's a good chance that nanosleep
will switch you out since you are explicitly asking to be put to sleep. It won't be so inefficient as to just put your process in a tight while
loop until the duration is over :-)
That means you're subject to all the vagaries of the scheduler including the fact that another process may totally use up its quanta, hence your process may be out of there for 100ms at least. On a heavily-enough loaded system, it could be out for quite a while.
回答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;
}
// it is much better than the usleep.
回答5:
you can use usleep
method to get sleep in microsecond units.
回答6:
Efficiency - an Os that allowed tasks to be switched in and out with a precision of a few clock cycles would do very little else.
There are specialized OSes that do this - but on regular hardware you pay a lot of overhead for the hypervisor
回答7:
This is a holding answer - I don't know the relevant linux internals, hopefully an expert can come along and clear it up.
One possibility is that that 69us is simply the raw overhead of descheduling and then rescheduling the thread. Even though the sleep is short, the kernel might do a lot of work to perform a context switch (or half a context switch, if there's nothing to schedule), and then undo it almost immediately. I don't know how long that "should" take on linux on a typical PC.
If that doesn't explain it, a scheduler generally has a concept of a "timeslice", which is how long a scheduled thread will be left to run before the scheduler thinks about switching it, unless it either deschedules itself or else something with higher priority becomes schedulable. The kernel will have low-level timers firing interrupts at the end of a time slice (in addition to interrupts that fire for certain other events such as I/O that could unblock a thread). When a timeslice ends, the scheduler can decide whether to continue with the same thread, or switch to another.
So it looks as though when you sleep, either (a) the scheduler isn't actually setting a timer that will make your thread schedulable at the requested time, it's just waiting for a timeslice, and so the CPU is going idle longer than necessary; or else (b) it is making your thread schedulable at the requested time, but when you gave up execution by sleeping, some other thread of equal priority got in, and the scheduler has no grounds to prefer you over it until it's "your turn" again according to whatever rules the scheduler usually uses to decide what thread to schedule.
69us is pretty short to be an artefact of timeslicing, though.
You seem to have a rudimentary solution - you can delay for very short periods by sitting in a loop checking the time, just like a spinlock. As everyone else is saying, though, in a non-realtime system, more or less by definition you can't demand that the scheduler runs your thread at any specific time. Even in a realtime system, if you're competing with threads of equal priority you may lose, and if you're competing with threads at higher priority you will lose.
来源:https://stackoverflow.com/questions/4986818/how-to-sleep-for-a-few-microseconds