Linux 如何睡几微秒
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4986818/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to sleep for a few microseconds
提问by Nikratio
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
在我的 2.6.32 系统上,结果是
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.
我同意这很可能是因为 nanosleep() 要求内核重新安排进程。我怎样才能避免这种情况?我想保留 CPU 的所有权并且只是闲置一段时间。
采纳答案by Yann Droneaud
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
- 为您的程序/线程使用实时调度程序类:SCHED_FIFO 或 SCHED_RR
- 提升您的程序/线程优先级
- 如果您要“睡眠”的时间少于内核将要处理的最小数量,请手动 busywait
Have a look at http://www.drdobbs.com/184402031
看看http://www.drdobbs.com/184402031
And this other question: nanosleep high cpu usage?
还有另一个问题:nanosleep CPU 使用率高?
回答by Anon.
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".
操作系统调度程序不会做任何事情,比如“哦,把这个线程从处理器上移开正好 86 个时钟周期,然后再把它放回去”。
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.
你放弃了处理器,你已经放弃了处理器。当感觉合适时,操作系统会让你重新开始。很有可能你必须等到其他正在运行的东西放弃处理器才能偷偷溜回去。
回答by paxdiablo
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
:-)
嗯,你必须学会忍受它,因为手册页指出,部分: 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 answerto 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.
现在至于您的问题的答案,我最好的猜测是因为您的第一个循环正在进程中运行。换句话说,不涉及上下文切换,因为您正在完全运行 CPU,并且您将在调度程序给您的 100 毫秒时间段内完成所有工作。
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 :-)
但是,nanosleep
由于您明确要求让您入睡,因此很有可能将您拒之门外。while
在持续时间结束之前将您的过程置于一个紧密的循环中不会那么低效:-)
That means you're subject to all the vagaries of the scheduler includingthe 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.
这意味着您会受到调度程序的所有变幻无常的影响,包括另一个进程可能完全用完它的量子这一事实,因此您的进程可能至少会离开那里 100 毫秒。在负载足够重的系统上,它可能会出现很长一段时间。
回答by Martin Beckett
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
有专门的操作系统可以执行此操作 - 但在常规硬件上,您需要为管理程序支付大量开销
回答by Steve Jessop
This is a holding answer - I don't know the relevant linux internals, hopefully an expert can come along and clear it up.
这是一个固定的答案 - 我不知道相关的 linux 内部原理,希望专家能来解决它。
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.
一种可能性是 69us 只是取消调度然后重新调度线程的原始开销。即使睡眠时间很短,内核也可能会做很多工作来执行上下文切换(或半个上下文切换,如果没有任何安排),然后几乎立即撤消它。我不知道在典型 PC 上的 linux 上“应该”需要多长时间。
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.
如果这不能解释它,调度程序通常有一个“时间片”的概念,即在调度程序考虑切换它之前,一个被调度的线程将运行多长时间,除非它自己取消调度或其他更高的优先级变得可调度。内核将有低级计时器在时间片结束时触发中断(除了为某些其他事件触发的中断,例如可以解除线程阻塞的 I/O)。当一个时间片结束时,调度器可以决定是继续同一个线程,还是切换到另一个线程。
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.
所以看起来好像当你睡觉时,要么 (a) 调度程序实际上并没有设置一个计时器来让你的线程在请求的时间被调度,它只是在等待一个时间片,所以 CPU 闲置的时间比必要的要长; 否则 (b) 它使您的线程可以在请求的时间进行调度,但是当您通过休眠放弃执行时,其他具有同等优先级的线程进入了,并且调度程序没有理由更喜欢您,直到“轮到您” "再次根据调度程序通常使用的任何规则来决定要调度的线程。
69us is pretty short to be an artefact of timeslicing, though.
不过,作为时间切片的产物,69us 非常短。
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 willlose.
您似乎有一个基本的解决方案 - 您可以通过坐在循环中检查时间来延迟很短的时间,就像自旋锁一样。但是,正如其他人所说,在非实时系统中,根据定义或多或少,您不能要求调度程序在任何特定时间运行您的线程。即使在实时系统中,如果您与同等优先级的线程竞争,您可能会失败,如果您与更高优先级的线程竞争,您将失败。
回答by Saurabh
you can use usleep
method to get sleep in microsecond units.
您可以使用usleep
method 以微秒为单位获得睡眠。
回答by bogao3037
// 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.
// 它比 usleep 好得多。