Chinaunix首页 | 论坛 | 博客
  • 博客访问: 285286
  • 博文数量: 60
  • 博客积分: 2697
  • 博客等级: 少校
  • 技术积分: 653
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-13 15:52
文章分类

全部博文(60)

文章存档

2012年(6)

2011年(31)

2010年(23)

分类: LINUX

2011-05-05 14:07:25

再论精确延时(usleep,nanosleep,select)

/*
        make:  gcc -o test_sleep test_sleep.c 
*/
/*        #include  "comm_main.h" */
#include ;
#include ;
#include ;
#include ;
#include ;
#include ;
#include ;
#include ;

#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函数.

 
阅读(5204) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~