美文网首页程序猿阵线联盟-汇总各类技术干货
深入理解linux下的短延迟:nanosleep,sleep

深入理解linux下的短延迟:nanosleep,sleep

作者: 风再起时ME | 来源:发表于2018-11-22 20:15 被阅读336次

    最近在使用nanosleep的时候又踩坑了。于是整理下linux短延迟的用法。

    用法

    回顾下秒的换算:ms(毫秒),μs(微秒),ns(纳秒),ps(皮秒)
    1s = 1000ms = 1000 * 1000us = 1000 * 1000 * 1000ns = 1000 * 1000 * 1000* 1000ps

    sleep()-------以秒为单位
    #include<unistd.h>
    unsigned int sleep(unsigned int seconds);
    return:若进程暂停到参数seconds 所指定的时间,成功则返回0,若有信号中断则返回剩余秒数。
    在linux中,sleep是通过nanosleep实现的。在一些其他系统中(例如POSIX.1),它是通过alarm()来实现的。
    
    usleep()----以微秒为单位
    #include<unistd.h>
    unsigned int usleep(unsigned int useconds);
    return:若进程暂停到参数seconds 所指定的时间,成功则返回0,若有信号中断则返回剩余微秒数。
    
    nanosleep( )---------以纳秒为单位
    #include<time.h>
     struct timespec
    {
      time_t  tv_sec;         /* 秒seconds */
      long    tv_nsec;        /* 纳秒nanoseconds */
    };
    int nanosleep(const struct timespec *req, struct timespec *rem);
    return: 若进程暂停到参数*req所指定的时间,成功则返回0,若有信号中断则返回-1,并且将剩余微秒数记录在*rem中。
    req->tv_sec是以秒为单位,而tv_nsec以毫微秒为单位(10的-9次方秒)。
    由于调用nanosleep是是进程进入TASK_INTERRUPTIBLE,这种状态是会相应信号而进入TASK_RUNNING状态的。
    

    函数的精确度与时钟的频率有关系
    我们假设时钟中断是10纳秒一次,如果tv_sec = 0, tv_nsec = 2,那么时钟中断一定是在10纳秒后来唤醒这个进程的,这里我们看到任务的重新调度最少是在10纳秒之上,因此此函数的精确程度与时钟频率有关系。
    cpu的速度决定了时钟周期; 如, 一個 50 MHz 的CPU, 一個时钟周期的时间是 1/50000000 s(200 nsec)。

    注意

    使用这些函数时一定要注意判断返回值。有时候会出现sleep函数被系统中断的情况,导致结果不符合预期。
    NANOSLEEP(2) BUGS

    // POSIX nanosleep may be interrupted by signals.
      while (nanosleep(&ts, &ts) == -1 && errno == EINTR) {}
    

    精确度对比

    低精度情况(100000us及以上):usleep和nanosleep表现差不多。select和pselect表现较差。
    高精度情况(100000us及以上):四者表现差不多。

                fuction  time(usec)    realtime      reduce
    ----------------------------------------------------
             usleep         500000     500091         91
             nanosleep      500000     500089         89
             select         500000     500540        540
             pselect        500000     500549        549
    --------------------------------
             usleep         100000     100078         78
             nanosleep      100000     100110        110
             select         100000     100157        157
             pselect        100000     100149        149
    --------------------------------
             usleep          50000      50091         91
             nanosleep       50000      50107        107
             select          50000      50111        111
             pselect         50000      50084         84
    --------------------------------
             usleep          10000      10086         86
             nanosleep       10000      10091         91
             select          10000      10089         89
             pselect         10000      10088         88
    --------------------------------
             usleep           1000       1089         89
             nanosleep        1000       1065         65
             select           1000       1065         65
             pselect          1000       1066         66
    --------------------------------
             usleep            900        969         69
             nanosleep         900        974         74
             select            900        970         70
             pselect           900        980         80
    --------------------------------
             usleep            500        569         69
             nanosleep         500        565         65
             select            500        569         69
             pselect           500        569         69
    --------------------------------
             usleep            100        166         66
             nanosleep         100        165         65
             select            100        163         63
             pselect           100        163         63
    --------------------------------
             usleep             10         73         63
             nanosleep          10         76         66
             select             10         73         63
             pselect            10         78         68
    --------------------------------
             usleep              1         64         63
             nanosleep           1         66         65
             select              1         65         64
             pselect             1         63         62
    --------------------------------
    

    测试代码:

    #include<stdio.h>
    #include<stdlib.h>
    #include<time.h>
    #include<sys/time.h>
    #include<errno.h>
    #include<string.h>
    #include<unistd.h>
    #include<sys/types.h>
    #include<sys/select.h>
     
     
    int main(int argc, char **argv)
    {
        unsigned int nTimeTestSec = 0;
        unsigned int nTimeTest = 0;
        struct timeval tvBegin;
        struct timeval tvNow;
        int ret = 0;
        unsigned int nDelay = 0;
        struct timeval tv;
        int fd = 1;
        int i = 0;
        struct timespec req;
     
        unsigned int delay[20] = 
            {500000, 100000, 50000, 10000, 1000, 900, 500, 100, 10, 1, 0};
        int nReduce = 0; //误差
     
        fprintf(stderr, "%19s%12s%12s%12s\n", "fuction", "time(usec)", "realtime", "reduce");
        fprintf(stderr, "----------------------------------------------------\n");
        for (i = 0; i < 20; i++)
        {
            if (delay[i] <= 0)
                break;
            nDelay = delay[i];
            //test sleep
            gettimeofday(&tvBegin, NULL);
            ret = usleep(nDelay);
            if(ret == -1)
            {
                fprintf(stderr, "usleep error, errno=%d [%s]\n", errno, strerror(errno));
            }
            gettimeofday(&tvNow, NULL);
            nTimeTest = (tvNow.tv_sec - tvBegin.tv_sec) * 1000000 + tvNow.tv_usec - tvBegin.tv_usec;
            nReduce = nTimeTest - nDelay;
     
             fprintf (stderr, "\t usleep       %8u   %8u   %8d\n", nDelay, nTimeTest,nReduce);
     
             //test nanosleep
             req.tv_sec = nDelay/1000000;
             req.tv_nsec = (nDelay%1000000) * 1000;
     
             gettimeofday(&tvBegin, NULL);
             ret = nanosleep(&req, NULL);
             if (-1 == ret)
             {
                fprintf (stderr, "\t nanousleep   %8u   not support\n", nDelay);
             }
             gettimeofday(&tvNow, NULL);
             nTimeTest = (tvNow.tv_sec - tvBegin.tv_sec) * 1000000 + tvNow.tv_usec - tvBegin.tv_usec;
             nReduce = nTimeTest - nDelay;
             fprintf (stderr, "\t nanosleep    %8u   %8u   %8d\n", nDelay, nTimeTest,nReduce);
     
             //test select
             tv.tv_sec = 0;
             tv.tv_usec = nDelay;
     
             gettimeofday(&tvBegin, NULL);
             ret = select(0, NULL, NULL, NULL, &tv);
             if (-1 == ret)
             {
                fprintf(stderr, "select error. errno = %d [%s]\n", errno, strerror(errno));
             }
     
             gettimeofday(&tvNow, NULL);
             nTimeTest = (tvNow.tv_sec - tvBegin.tv_sec) * 1000000 + tvNow.tv_usec - tvBegin.tv_usec;
             nReduce = nTimeTest - nDelay;
             fprintf (stderr, "\t select       %8u   %8u   %8d\n", nDelay, nTimeTest,nReduce);
     
             //pselcet
             req.tv_sec = nDelay/1000000;
             req.tv_nsec = (nDelay%1000000) * 1000;
     
             gettimeofday(&tvBegin, NULL);
             ret = pselect(0, NULL, NULL, NULL, &req, NULL);
             if (-1 == ret)
             {
                fprintf(stderr, "select error. errno = %d [%s]\n", errno, strerror(errno));
             }
     
             gettimeofday(&tvNow, NULL);
             nTimeTest = (tvNow.tv_sec - tvBegin.tv_sec) * 1000000 + tvNow.tv_usec - tvBegin.tv_usec;
             nReduce = nTimeTest - nDelay;
             fprintf (stderr, "\t pselect      %8u   %8u   %8d\n", nDelay, nTimeTest,nReduce);
     
             fprintf (stderr, "--------------------------------\n");
     
        }
        
        return 0;
    }
    

    相关文章

      网友评论

        本文标题:深入理解linux下的短延迟:nanosleep,sleep

        本文链接:https://www.haomeiwen.com/subject/trfrfqtx.html