µ;C for linux中的s-precision wait不会使程序进入睡眠状态?
我真的很想在C程序中实现25µs的延迟,我正在编写该程序,以便通过RPI3读取传感器。我使用了nanosleep()和usleep(),但精确度似乎有点低——可能是因为程序将线程时间割让给了其他程序,然后必须等待它们完成。我使用“nice-n-20”来确保优先级,但它似乎仍然没有我想要的那么准确。我也尝试过for循环,但不能完全确定时钟滴答声:for循环计数比率需要达到25µs(我对这一切都很陌生)。。。或者gcc正在将空循环优化为遗忘µ;C for linux中的s-precision wait不会使程序进入睡眠状态?,c,sensors,raspberry-pi3,C,Sensors,Raspberry Pi3,我真的很想在C程序中实现25µs的延迟,我正在编写该程序,以便通过RPI3读取传感器。我使用了nanosleep()和usleep(),但精确度似乎有点低——可能是因为程序将线程时间割让给了其他程序,然后必须等待它们完成。我使用“nice-n-20”来确保优先级,但它似乎仍然没有我想要的那么准确。我也尝试过for循环,但不能完全确定时钟滴答声:for循环计数比率需要达到25µs(我对这一切都很陌生)。。。或者gcc正在将空循环优化为遗忘 不管怎样,有人能给我指出microDelay()函数或类似
不管怎样,有人能给我指出microDelay()函数或类似的东西的方向吗?(我花了几个小时在谷歌上搜索和试验,但似乎找不到我想要的东西)。谢谢 在没有硬件支持的传统多任务操作系统中,实现这种低分辨率(小于1ms)几乎是不可能的,但有一种软件技术可以帮助您。(我以前测试过)
由于操作系统调度程序抢占进程,软件延迟循环不是精确的解决方案。但是你可以用RT_PREEMPT修补你的内核,并通过CONFIG_RT_PREEMPT启用它,现在你有了一个支持实时调度的内核,实时内核让你运行一个具有实时优先级的进程,具有实时优先级的进程运行,直到它想要没有人可以抢占它,因此,如果您运行一个延迟循环,该过程将不会被操作系统抢占,因此您可以使用这些循环创建精确的延迟。在没有硬件支持的传统多任务操作系统中,实现如此低的分辨率(小于1ms)几乎是不可能的,但有一种软件技术可以帮助您。(我以前测试过)
由于操作系统调度程序抢占进程,软件延迟循环不是精确的解决方案。但是你可以用RT_PREEMPT修补你的内核,并通过CONFIG_RT_PREEMPT启用它,现在你有了一个支持实时调度的内核,实时内核让你运行一个具有实时优先级的进程,具有实时优先级的进程运行,直到它想要没有人可以抢占它,因此,如果您运行延迟循环,进程将不会被操作系统抢占,因此您可以使用这些循环创建精确的延迟。Linux 2中有一点。nanosleep对在实时策略(如SCHED_FIFO或SCHED_RR)下调度的进程有特定的行为,当指定的睡眠被激活时,它会忙着等待低于最低时钟分辨率或粒度,但已被删除。(试试曼·纳纳索普,我相信这里提到过这种行为) 我需要有一个更精确的睡眠时间间隔,所以我写了自己的版本来调用这些特殊情况。在目标机器上,我能够获得<10µs的延迟,只有偶尔的光点(参见代码中的注释) 请记住,对于非实时调度策略,如果您的应用程序尝试以低于最小时钟分辨率的时间休眠,它仍可能被抢占 下面是我编写的一个小测试程序,用于测试这一点,忙循环调用clock_gettime(),以便知道何时该唤醒:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <signal.h>
void usage(char *name, const char *msg)
{
if ( msg )
fprintf(stderr,"%s\n",msg);
fprintf(stderr,"Usage: %s, -s<sleepNanoseconds> [-c<loopCount>] [-e]\n", name);
fprintf(stderr," -s<sleepNanoseconds> is the number nanoseconds to busy-sleep, usually < 60000\n");
fprintf(stderr," -c<loopCount> the number of loops to execute the busy sleep, default 1000000 \n");
fprintf(stderr," -e do not calculate min, max and avg. only elapsed time \n");
}
# define tscmp(a, b, CMP) \
(((a)->tv_sec == (b)->tv_sec) ? \
((a)->tv_nsec CMP (b)->tv_nsec) : \
((a)->tv_sec CMP (b)->tv_sec))
# define tsadd(a, b, result) \
do { \
(result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
(result)->tv_nsec = (a)->tv_nsec + (b)->tv_nsec; \
if ((result)->tv_nsec >= 1000000000) \
{ \
++(result)->tv_sec; \
(result)->tv_nsec -= 1000000000; \
} \
} while (0)
# define tssub(a, b, result) \
do { \
(result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
(result)->tv_nsec = (a)->tv_nsec - (b)->tv_nsec; \
if ((result)->tv_nsec < 0) { \
--(result)->tv_sec; \
(result)->tv_nsec += 1000000000; \
} \
} while (0)
///////////////////////////////////////////////////////////////////////////////
///
/// busySleep uses clock_gettime and a elapsed time check to provide delays
/// for less than the minimum sleep resolution (~58 microseconds). As tested
/// on a XEON E5-1603, a sleep of 0 yields a delay of >= 375 Nsec, 1-360 about
/// 736 Nsec, 370-720 a little more than 1 Usec, 720-1080 a little less than
/// 1.5 Usec and generally it's pretty linear for delays of 10 Usec on up in
/// increments of 10 Usec, e.g., 10 Usec =~ 10.4, 20 Usec =~ 20.4 and so on.
///
///////////////////////////////////////////////////////////////////////////////
int busySleep( uint32_t nanoseconds )
{
struct timespec now;
struct timespec then;
struct timespec start;
struct timespec sleep;
if ( nanoseconds > 999999999 )
{
return 1;
}
clock_gettime( CLOCK_MONOTONIC_RAW, &start);
now = start;
sleep.tv_sec = 0;
sleep.tv_nsec = nanoseconds;
tsadd( &start, &sleep, &then );
while ( tscmp( &now, &then, < ) )
{
clock_gettime( CLOCK_MONOTONIC_RAW, &now);
}
return 0;
}
int main(int argc, char **argv)
{
uint32_t sleepNsecs = 1000000000;
uint32_t loopCount = 1000000;
bool elapsedOnly = false;
uint32_t found = 0;
int opt;
if ( argc < 2 )
{
sleepNsecs = atol(argv[1]);
usage( argv[0], "Required options were not given" );
return 1;
}
while ( (opt = getopt(argc, argv, "s:d:e")) != -1 )
{
switch ( opt )
{
case 's':
sleepNsecs = strtoul(optarg,NULL,0);
break;
case 'd':
loopCount = strtoul(optarg,NULL,0);
break;
case 'e':
elapsedOnly = true;
break;
default:
usage(argv[0],"Error: unrecognized option\n");
return 1;
}
found++;
}
if ( found < 1 )
{
usage( argv[0], "Invalid command line." );
return 1;
}
if ( sleepNsecs > 999999999 )
{
usage( argv[0], "Sleep nanoseconds must be less than one second." );
return 1;
}
printf("sleepNsecs set to %d\n",sleepNsecs);
struct timespec start;
struct timespec now;
struct timespec prev;
struct timespec elapsed;
struct timespec trem;
uint64_t count = 0;
int64_t sum = 0;
int64_t min = 99999999;
int64_t max = 0;
clock_gettime( CLOCK_MONOTONIC_RAW, &start);
now = start;
prev = start;
//while ( tscmp( &now, &then, < ) )
for ( uint32_t i = 0; i < loopCount; i++ )
{
int rc = busySleep( sleepNsecs );
if ( rc != 0 )
{
fprintf( stderr, "busySleep returned an error!\n" );
return 1;
}
if ( ! elapsedOnly )
{
clock_gettime( CLOCK_MONOTONIC_RAW, &now);
tssub( &now, &prev, &trem );
min = ( min < trem.tv_nsec ? min : trem.tv_nsec );
max = ( max > trem.tv_nsec ? max : trem.tv_nsec );
count++;
sum += trem.tv_nsec;
prev = now;
}
}
if ( ! elapsedOnly )
{
printf("Min: %lu, Max: %lu, avg %lu, count %lu\n",min,max,(sum / count),count);
}
else
{
clock_gettime( CLOCK_MONOTONIC_RAW, &now);
tssub( &now, &start, &elapsed );
double secs = ((double)elapsed.tv_sec) + ((double) elapsed.tv_nsec / (double)1e9 );
fprintf( stderr, "Elapsed time of %ld.%09ld for %u sleeps of duration %u, avg. = %.9f Ns\n",
elapsed.tv_sec, elapsed.tv_nsec, loopCount, sleepNsecs, (secs / loopCount) );
}
return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
无效用法(字符*名称,常量字符*消息)
{
如果(味精)
fprintf(stderr,“%s\n”,msg);
fprintf(标准,“用法:%s,-s[-c][e]\n”,名称);
fprintf(stderr,“-s是繁忙睡眠的纳秒数,通常<60000\n”);
fprintf(stderr,“-c执行忙睡眠的循环数,默认为1000000\n”);
fprintf(stderr,“-e不计算最小值、最大值和平均值。仅计算经过的时间\n”);
}
#定义tscmp(a、b、CMP)\
((a)->电视秒==(b)->电视秒)\
((a)->tv\u nsec CMP(b)->tv\u nsec):\
((a)->tv_seccmp(b)->tv_seccmp))
#定义tsadd(a、b、结果)\
做{\
(结果)->tv_-sec=(a)->tv_-sec+(b)->tv_-sec\
(结果)->tv_nsec=(a)->tv_nsec+(b)->tv_nsec\
如果((结果)->tv\u nsec>=100000000)\
{ \
++(结果)->tv_秒\
(结果)->tv_nsec-=100000000\
} \
}而(0)
#定义tssub(a、b、结果)\
做{\
(结果)->tv_-sec=(a)->tv_-sec-(b)->tv_-sec\
(结果)->tv\u nsec=(a)->tv\u nsec-(b)->tv\u nsec\
如果((结果)->tv_nsec<0){\
--(结果)->tv_秒\
(结果)->tv_nsec+=100000000\
} \
}而(0)
///////////////////////////////////////////////////////////////////////////////
///
///busySleep使用时钟获取时间和运行时间检查来提供延迟
///低于最低睡眠分辨率(~58微秒)。经检验
///在XEON E5-1603上,睡眠为0会产生大于等于375纳秒的延迟,约为1-360纳秒
///736 Nsec,370-720略高于1 Usec,720-1080略低于
///1.5usec,通常情况下,对于10 Usec以上的延迟,它是相当线性的
///增量为10 Usec,例如,10 Usec=~10.4,20 Usec=~20.4等等。
///
///////////////////////////////////////////////////////////////////////////////
int busySleep(单位32纳秒)
{
现在构造timespec;
然后构造timespec;
结构timespec启动;
结构timespec睡眠;
如果(纳秒>9999999)
{
返回1;
}
时钟获取时间(时钟单调、原始和开始);
现在=开始;
sleep.tv_sec=0;
sleep.tv\u nsec=纳秒