zoukankan      html  css  js  c++  java
  • 关于短延迟 sleep usleep nanosleep select

    http://www.cppblog.com/prayer/archive/2008/08/21/59572.html

    udelay(unsigned long usecs);
    mdelay(unsigned long msecs);
    前者用软件循环指定的微妙数,后者调用前者达到延迟毫秒级。udelay 函数只能用于获取较短的时间延迟,因为loops_per_second值的精度只有8位,所以,当计算更长的延迟时会积累出相当大的误差。尽管最大能允许的延迟将近1秒(因为更长的延迟就要溢出),推荐的 udelay 函数的参数的最大值是取1000微秒(1毫秒)。延迟大于 11 毫秒时可以使用函数 mdelay。
    要特别注意的是 udelay 是个忙等待函数(所以 mdelay 也是),在延迟的时间段内无法运行其他的任务,因此要十分小心,尤其是 mdelay,除非别无他法,要尽量避免使用。
    mdelay 在 Linux 2.0 中并不存在,头文件 sysdep.h 弥补了这一缺陷。
    关于 usleep sleep 主要的差距在精确程度上,不过网友有关于这个方面的精辟论断:
    同样我觉得select也是比较好的定时机制,不过大家可以看igmp-proxy的源代码。主函数里面用setitimer和select同时定时是一个相当好的想法。
    #################################################################
    再论精确延时(usleep,nanosleep,select)

    /*
            make: gcc -o test_sleep test_sleep.c
    */
    /*        #include "comm_main.h" */
    #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>;

    #define PRINT_USEAGE { \
       fprintf(stderr,"\n Usage: %s usec ",argv[0]); \
       fprintf(stderr,"\n\n");\
    }

    int
    main (int argc, char **argv)
    {
    unsigned int nTimeTestSec = 0;        /* sec */
    unsigned int nTimeTest = 0;        /* usec */
    struct timeval tvBegin;
    struct timeval tvNow;
    int ret = 0;
    unsigned int nDelay = 0;        /* usec */
    fd_set rfds;
    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;                /* 误差 */

    #if 0
    if (argc < 2)
        {
          PRINT_USEAGE;
          exit (1);
        }
    nDelay = atoi (argv[1]);
    #endif

    fprintf (stderr, "%18s%12s%12s%12s\n", "function", "time(usec)", "realTime",
               "reduce");
    fprintf (stderr,
               "-------------------------------------------------------------------\n");

    for (i = 0; i < 20; i++)
        {
          if (delay[i] <= 0)
            break;
          nDelay = delay[i];

          /*      test usleep */
          gettimeofday (&tvBegin, NULL);
          ret = usleep (nDelay);
          if (-1 == ret)
            {
              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 */
          gettimeofday (&tvBegin, NULL);
          req.tv_sec = nDelay / 1000000;
          req.tv_nsec = (nDelay % 1000000) * 1000;
          ret = nanosleep (&req, NULL);
          if (-1 == ret)
            {
              fprintf (stderr, "\t nanosleep    %8u   not support\n", nDelay);
            }
          else
            {
              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 */
          gettimeofday (&tvBegin, NULL);
          FD_ZERO (&rfds);
          FD_SET (fd, &rfds);
          tv.tv_sec = 0;
          tv.tv_usec = nDelay;
          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);

        }

    return 0;
    }

    ---------------------------------------------------------------------------------------------------------------------------------------------------

    测试
    IBM AIX 3.4 单CPU
            sleep 可以在多线程中使用,只阻塞本线程,不影响所属进程中的其它线程
            不支持 nanosleep
            支持 usleep 和 select
            以下采用 gettimeofday 对 usleep 和 select 的实际精确情况进行测试分析
              function time(usec)    realTime      reduce
    -------------------------------------------------------------------
             usleep         500000     500026         26
             nanosleep      500000   not support
             select         500000     500026         26
             usleep         100000     100021         21
             nanosleep      100000   not support
             select         100000     100025         25
             usleep          50000      50021         21
             nanosleep       50000   not support
             select          50000      50107        107
             usleep          10000      10099         99
             nanosleep       10000   not support
             select          10000      10025         25
             usleep           1000       1021         21
             nanosleep        1000   not support
             select           1000       1024         24
             usleep            900        920         20
             nanosleep         900   not support
             select            900       1024        124
             usleep            500        523         23
             nanosleep         500   not support
             select            500       1024        524
             usleep            100        119         19
             nanosleep         100   not support
             select            100       1023        923
             usleep             10         31         21
             nanosleep          10   not support
             select             10       1024       1014
             usleep              1         19         18
             nanosleep           1   not support
             select              1       1026       1025

    由此可以得出,在AIX 3.4下:
             select 只能精确到毫秒级别
             usleep 可以精确到微秒级
             在1毫秒以上,两者的精确度基本一样

    同上,在 linux 2.4.20-8smp 双CPU 下测试
              function time(usec)    realTime      reduce
    -------------------------------------------------------------------
             usleep         500000     506453       6453
             nanosleep      500000     509930       9930
             select         500000     499990        -10
             usleep         100000     110023      10023
             nanosleep      100000     109955       9955
             select         100000      99992         -8
             usleep          50000      59971       9971
             nanosleep       50000      59990       9990
             select          50000      50025         25
             usleep          10000      19991       9991
             nanosleep       10000      19988       9988
             select          10000       9956        -44
             usleep           1000      19990      18990
             nanosleep        1000      19989      18989
             select           1000      10024       9024
             usleep            900      20009      19109
             nanosleep         900      19972      19072
             select            900       9943       9043
             usleep            500      19975      19475
             nanosleep         500      19971      19471
             select            500      10012       9512
             usleep            100      19975      19875
             nanosleep         100      19976      19876
             select            100       9943       9843
             usleep             10      19988      19978
             nanosleep          10      19961      19951
             select             10      10011      10001
             usleep              1      19978      19977
             nanosleep           1      19985      19984
             select              1       9932       9931
    在 2.4.21-4.ELsmp #1 SMP 4 CPU 下测试
               function time(usec)    realTime      reduce
    -------------------------------------------------------------------
             usleep         500000     501267       1267
             nanosleep      500000     509964       9964
             select         500000     499981        -19
             usleep         100000     109944       9944
             nanosleep      100000     109925       9925
             select         100000      99963        -37
             usleep          50000      59904       9904
             nanosleep       50000      59973       9973
             select          50000      49956        -44
             usleep          10000      19988       9988
             nanosleep       10000      20008      10008
             select          10000      10020         20
             usleep           1000      19988      18988
             nanosleep        1000      19980      18980
             select           1000       9943       8943
             usleep            900      19975      19075
             nanosleep         900      19986      19086
             select            900       9905       9005
             usleep            500      19989      19489
             nanosleep         500      19910      19410
             select            500      10000       9500
             usleep            100      19355      19255
             nanosleep         100      19902      19802
             select            100       9988       9888
             usleep             10      19977      19967
             nanosleep          10      19988      19978
             select             10       9943       9933
             usleep              1      20007      20006
             nanosleep           1      19947      19946
             select              1       9980       9979
    由此可以得出如下结论,在 linux 2.4 下:
              1、支持 usleep,nanosleep,select
              2、select 的 精确度为 10毫秒。在10毫秒以上很精确
              3、usleep, nanosleep 很不精确

    同样,通过其它测试程序能得出如下结论:
              sleep 可以在多线程中使用,只阻塞本线程,不影响所属进程中的其它线程

    usleep()有有很大的问题

    1. 在一些平台下不是线程安全,如HP-UX以及Linux
    2. usleep()会影响信号
    3. 在很多平台,如HP-UX以及某些Linux下,当参数的值必须小于1 * 1000 * 1000也就是1秒,否则该函数会报错,并且立即返回。
    4. 大部分平台的帮助文档已经明确说了,该函数是已经被舍弃的函数。

    还好,POSIX规范中有一个很好用的函数,nanosleep(),该函数没有usleep()的这些缺点,它的精度是纳秒级。在Solaris的多线程环境下编译器会自动把usleep()连接成nanosleep()。

    Linux下短延时推荐使用select函数.

  • 相关阅读:
    MySql常用数据操作
    使用requests+BeaBeautiful Soup爬取妹子图图片
    抓取猫眼电影排行
    Exec执行拼接字符串时遇到的问题及Sql执行函数时需要注意的事项
    c#小知识点
    MVVM 与 sql
    Dictionary
    sql表信息查询
    XAML特殊字符
    编程细节
  • 原文地址:https://www.cnblogs.com/leaven/p/1771417.html
Copyright © 2011-2022 走看看