更新:代码中的固定增量计算,问题仍然存在
伙计们,请您解释为什么我不时会使用以下代码得到非常奇怪的结果:
#include <unistd.h>
#include <sys/time.h>
#include <stdio.h>
int main()
{
struct timeval start, end;
long mtime1, mtime2, diff;
while(1)
{
gettimeofday(&start, NULL);
usleep(2000);
gettimeofday(&end, NULL);
mtime1 = (start.tv_sec * 1000 + start.tv_usec/1000.0);
mtime2 = (end.tv_sec * 1000 + end.tv_usec/1000.0);
diff = mtime2 - mtime1;
if(diff > 10)
printf("WTF: %ld\n", diff);
}
return 0;
}
(你可以编译并运行它: gcc test.c -o out -lrt&amp;&amp; ./out)
我所经历的是差异变量的零星大值几乎每秒或更频繁,例如:
$ gcc test.c -o out -lrt && ./out
WTF: 14
WTF: 11
WTF: 11
WTF: 11
WTF: 14
WTF: 13
WTF: 13
WTF: 11
WTF: 16
这怎么可能?是操作系统的责任吗?是否进行了太多的上下文切换?但我的盒子闲置了( 平均负荷:0.02,0.02,0.3)。
这是我的Linux内核版本:
$ uname -a
Linux kurluka 2.6.31-21-generic #59-Ubuntu SMP Wed Mar 24 07:28:56 UTC 2010 i686 GNU/Linux
答案 0 :(得分:4)
睡眠功能只能确保您至少在一定时间内睡觉。由于Linux不是一个实时操作系统,你不能确定它只会睡觉你想要的时间。这是一个问题,因为你不能指望这个值。正如你所指出的那样,睡眠时间真的很大。
Linux调度程序无法保证。使用实时操作系统,您可以获得该功能。
你的公式在某种程度上是错误的,但我认为这不是你有如此大的睡眠时间的原因。我用这个片段检查了两个公式,结果相同:
#include <unistd.h>
#include <sys/time.h>
#include <time.h>
#include <stdio.h>
int main()
{
struct timeval start, end;
long mtime, mtime2, start_time, end_time, seconds, useconds;
while(1)
{
gettimeofday(&start, NULL);
usleep(2000);
gettimeofday(&end, NULL);
seconds = end.tv_sec - start.tv_sec;
useconds = end.tv_usec - start.tv_usec;
mtime = ((seconds) * 1000 + useconds/1000.0) + 0.5;
start_time = ((start.tv_sec) * 1000 + start.tv_usec/1000.0) + 0.5;
end_time = ((end.tv_sec) * 1000 + end.tv_usec/1000.0) + 0.5;
mtime2 = end_time - start_time;
if(mtime > 10 || mtime2 > 10)
{
printf("WTF: %ld\n", mtime);
printf("WTF2: %ld\n", mtime2);
}
}
return 0;
}
结果:
$ gcc test.c -o out -lrt && ./out
WTF: 11
WTF2: 12
WTF: 21
WTF2: 21
我认为这是错误的,因为useconds部分是循环的并且可能导致很大的负面差异。但它不会导致你使用签名长整数这么大的时间......
my2cents
编辑:来自man nanosleep:
当前的实施 nanosleep()基于正常 内核计时器机制,它有一个 分辨率为1 / HZ s(见时间(7))。 因此,nanosleep()总是暂停 至少在指定的时间内, 但是它可能需要长达10毫秒 直到过程指定 再次变得可以运行。对于相同的 原因,在以下情况下返回的值 * rem中的传递信号通常是 四舍五入到下一个更大的倍数 1 / HZ s。
答案 1 :(得分:2)
我的猜测是它与操作系统有关。尝试以实时优先级运行该进程(请参阅chrt程序),看看是否有帮助。
另一方面,你正在计算错误的mtime。这是'我使用的例程,虽然它是struct timespec而不是struct timeval(纳秒而不是微秒),原则应该是明确的:
timespec diff(timespec start, timespec end)
{
timespec temp;
if ((end.tv_nsec - start.tv_nsec) < 0) {
temp.tv_sec = end.tv_sec - start.tv_sec - 1;
temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec;
} else {
temp.tv_sec = end.tv_sec - start.tv_sec;
temp.tv_nsec = end.tv_nsec - start.tv_nsec;
}
return temp;
}
答案 2 :(得分:1)
找到它,参见手册页
http://linux.die.net/man/3/usleep
以系统定时器的粒度。
这是10毫秒afaik。因此,usleep
可以在重新安排流程之前很久就会过期。
它与你得到的值一致,它们是“正常”时间片的数量级。
答案 3 :(得分:0)
你的公式错了。您必须以相同的比例转换两次。在你的例子中。
double mtime1 = (start.tv_sec * 1000 + start.tv_usec/1000.0) ;
double mtime2 = (end.tv_sec * 1000 + end.tv_usec/1000.0) ;
double diff = mtime2 - mtime1;
if(diff > 10)
printf("WTF: %ld\n", diff);
您必须减去更正后的值
示例:t1 = 1.999999 t2 = 2.000001
所以间隔为2μs
使用您的公式计算:
2 - 1 == 1
和1 - 9999999
给出(1 * 1000 - 999998 / 1000) + 0.5
==的结果
0.502这显然是假的。
我的方法给出:
mtime1 = (1 * 1000 + 999999 / 1000) = 1999.999
mtime2 = (2 * 1000 + 1 / 1000) = 2000.001
2000.001 - 1999.999 = 0.002 ms
答案 4 :(得分:0)
我已经做过这样的措施,我的结论完全相同。在Windows和Linux上同样发生。
在10 ^ -n秒内构建直方图的程序会得到以下结果。
0.1 0
0.01 0
0.001 0
0.0001 2
1e-05 24
1e-06 69726023
Total: 69726049
Duration: 6.47403 seconds.
Average: 0.0928495 microseconds.
但请注意,这是一个全新的系统。我记得一年前在2004系统上使用它,并且在0.01范围内(10毫秒以上)每秒有几次点击。