如何在 C(Linux)中的 while 循环中准确睡眠?
Posted
技术标签:
【中文标题】如何在 C(Linux)中的 while 循环中准确睡眠?【英文标题】:how to sleep accurately in a while loop in C (Linux)? 【发布时间】:2015-06-18 11:39:35 【问题描述】:在 C 代码(Linux 操作系统)中,我需要在一个 while 循环内准确地休眠 - 比如说,10000 微秒,共 1000 次。我试过usleep、nanosleep、select、pselect和其他一些方法都没有成功。 在大约 50 次中,它的睡眠时间会延长 %100(大约 20000 我们)。 我需要在每次延迟后执行一个动作。因此,每个延迟都必须非常准确。 有没有办法为这种情况做准确的睡眠? 谢谢..
编辑:
#include <stdio.h>
#include <sys/time.h>
int main(int argc, char *argv[])
struct timespec t0, t1;
long err;
int i = 0;
while (i < 1000)
clock_gettime(CLOCK_MONOTONIC, &t0);
usleep(10000);
clock_gettime(CLOCK_MONOTONIC, &t1);
err = (long) ((t1.tv_sec - t0.tv_sec) * 1e6
+ (t1.tv_nsec - t0.tv_nsec) / 1000) - 10000;
printf("i = %d err = %ld\n", i, err);
i++;
return 0;
结果(日志文件):
i = 0 err = -146i = 1 err = -207i = 2 err = -8i = 3 err = -4i = 4 err = -22 i = 5 err = 31i = 6 err = -45i = 7 err = 9i = 8 err = 61i = 9 err = -71 i = 10 err = -24i = 11 err = 14i = 12 err = -12i = 13 err = -32i = 14 err = -15i = 15 错误 = 42i = 16 错误 = -51i = 17 错误 = -19i = 18 错误 = -12i = 19 错误 = 4i = 20错误 = 12i = 21 错误 = -36i = 22 错误 = -38i = 23 错误 = 18i = 24 错误 = 1i = 25 错误 = - 21i = 26 err = -37i = 27 err = 31i = 28 err = -4i = 29 err = -45i = 30 err = -37 i = 31 错误 = 20i = 32 错误 = -10i = 33 错误 = -5i = 34 错误 = -12i = 35 错误 = -5i = 36 err = -10i = 37 err = -12i = 38 err = -2i = 39 err = 14i = 40 err = -34i = 41 错误 = -10i = 42 错误 = -6i = 43 错误 = 15i = 44 错误 = -34i = 45 错误 = -12 i = 46 错误 = -15i = 47 错误 = -25i = 48 错误 = 11614i = 49 错误 = 2340i = 50 错误 = 589i = 5 1 错误 = 12254i = 52 错误 = -93i = 53 错误 = -19
【问题讨论】:
请让我们看看您使用usleep()
的尝试。这不是一个实时操作系统,但我不敢相信它有这么大的差距。
您确定您指示的 200 毫秒延迟取决于 usleep 功能吗?您是否确认此延迟不依赖于 ISR(中断子例程)或其他类型的系统事件?
我已经编辑了我的问题。对不起,输入错误的数字。由于日志文件,error仍然很高(i = 212时大约50%)。
感谢您的快速回答.. 仍然没有成功..
【参考方案1】:
睡眠时间较短,然后轮询高频计数器以完成延迟。将所有延迟都基于计数器的原始读数,以防止随时间漂移。例如,previous_count = counter(), wait_count = previous_count + delay_count, delay until counter() - wait_count >= 0, previous_count += delay_count, ... 。如果所需的频率不是 counter() 频率的精确倍数,则使用一个变量来表示延迟的小数部分(我称之为剩余计数)。
由于您提到了 Windows,这里是一个以固定频率运行的线程的示例,并且与 Windows XP 兼容,其中 Sleep(1) 最多可能需要 2 毫秒。 dwLateStep 是一种调试辅助工具,每次循环时间过长时都会增加(如果可能,它会赶上)。延迟基于计数器的原始读数(使用 uWait、uRem、uPrev、uDelta),因此在很长一段时间内没有漂移。这基本上是游戏实现固定频率物理线程的方式。请注意,.net 框架不用于这些类型的游戏,因为它会间歇性地暂停进程以重新打包分页内存。此类游戏会将物理线程优先级设置为高于正常水平,以防止其他线程或进程对其进行干扰。
typedef unsigned long long UI64; /* unsigned 64 bit int */
#define FREQ 400 /* frequency */
DWORD dwLateStep; /* late step count */
LARGE_INTEGER liPerfFreq; /* 64 bit frequency */
LARGE_INTEGER liPerfTemp; /* used for query */
UI64 uFreq = FREQ; /* process frequency */
UI64 uOrig; /* original tick */
UI64 uWait; /* tick rate / freq */
UI64 uRem = 0; /* tick rate % freq */
UI64 uPrev; /* previous tick based on original tick */
UI64 uDelta; /* current tick - previous */
UI64 u2ms; /* 2ms of ticks */
UI64 i;
/* ... */ /* wait for some event to start thread */
QueryPerformanceFrequency(&liPerfFreq);
u2ms = ((UI64)(liPerfFreq.QuadPart)+499) / ((UI64)500);
timeBeginPeriod(1); /* set period to 1ms */
Sleep(128); /* wait for it to stabilize */
QueryPerformanceCounter((PLARGE_INTEGER)&liPerfTemp);
uOrig = uPrev = liPerfTemp.QuadPart;
for(i = 0; i < (uFreq*30); i++)
/* update uWait and uRem based on uRem */
uWait = ((UI64)(liPerfFreq.QuadPart) + uRem) / uFreq;
uRem = ((UI64)(liPerfFreq.QuadPart) + uRem) % uFreq;
/* wait for uWait ticks */
while(1)
QueryPerformanceCounter((PLARGE_INTEGER)&liPerfTemp);
uDelta = (UI64)(liPerfTemp.QuadPart - uPrev);
if(uDelta >= uWait)
break;
if((uWait - uDelta) > u2ms)
Sleep(1);
if(uDelta >= (uWait*2))
dwLateStep += 1;
uPrev += uWait;
/* fixed frequency code goes here */
/* along with some type of break when done */
/* otherwise, this example runs for 30 seconds */
timeEndPeriod(1); /* restore period */
【讨论】:
感谢您的回答。我也试过你的方法。抱歉,没有成功。我不是专业程序员,但在我看来,在执行操作时程序会尝试释放内存,这会减慢进程.. 如果进程被暂停以重新打包释放的内存,请尝试提前预分配您需要的内存,并避免进一步释放或分配内存。如果这是由于其他应用程序正在运行,那么您无能为力(假设您无法提高程序的优先级)。 您能解释一下如何为这种特定情况预分配内存吗? @ayadev - 如果您的程序可以使用固定或最大内存量运行,请在程序开始时分配所有内存,并且在程序退出之前不要释放任何内存。您可能需要在程序中创建某种内部内存管理。 我再次编辑了我的问题。您可以自己编译代码以查看您的操作系统的结果,我的是 Windows 7。我不知道如何为 int、long 和 timespec 变量分配内存..你能给我一个适合你的例子吗?谢谢..以上是关于如何在 C(Linux)中的 while 循环中准确睡眠?的主要内容,如果未能解决你的问题,请参考以下文章