µ;C for linux中的s-precision wait不会使程序进入睡眠状态?

µ;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()函数或类似

我真的很想在C程序中实现25µs的延迟,我正在编写该程序,以便通过RPI3读取传感器。我使用了nanosleep()和usleep(),但精确度似乎有点低——可能是因为程序将线程时间割让给了其他程序,然后必须等待它们完成。我使用“nice-n-20”来确保优先级,但它似乎仍然没有我想要的那么准确。我也尝试过for循环,但不能完全确定时钟滴答声:for循环计数比率需要达到25µs(我对这一切都很陌生)。。。或者gcc正在将空循环优化为遗忘


不管怎样,有人能给我指出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=纳秒