linux不靠谱的sleep

首先感谢如下两篇的blog,让我走出了很大的一个误区:


http://www.cppblog.com/kongque/archive/2011/01/18/138765.aspx

http://blog.csdn.net/zjwoody/article/details/7882240


在我的一个项目中,因为需要与串口通信,每次读写都需要延时usleep(1000)=1ms,但是通信量非常大,每一次工作这样的通信大概有300次左右,这样算下耗时应该是300ms左右。


但是通过strace打印出系统函数调用发现实际接近900ms,仔细观察strace日志才发现,每次usleep(1000000)其实都延时了2ms,之后上网搜索才发现usleep是不精确的。


1.sleep的精度是秒
2.usleep的精度是微妙,不精确
3.select的精度是微妙,精确
    struct timeval delay;
    delay.tv_sec = 0;
    delay.tv_usec = 20 * 1000; // 20 ms
    select(0, NULL, NULL, NULL, &delay);

4.nanosleep的精度是纳秒,不精确

unix、linux系统尽量不要使用usleep和sleep而应该使用nanosleep,使用nanosleep应注意判断返回值和错误代码,否则容易造成cpu占用率100%。

这是第一篇blog中提到的,然后第二篇blog中提供的测试代码,本人做了少量改动(原作者没有打印出usleep(0)时的信息),代码如下:

/*
        make:  gcc -o test_sleep test_sleep.c 
*/
#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 < 11; 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;
}

程序显示如下:

[root@localhost test]# ./sleep_com 
          function  time(usec)    realTime      reduce
-------------------------------------------------------------------
/t usleep         500000     501575       1575
/t nanosleep      500000     501861       1861
/t select         500000     499893       -107
/t usleep         100000     101933       1933
/t nanosleep      100000     101957       1957
/t select         100000      99946        -54
/t usleep          50000      51954       1954
/t nanosleep       50000      51962       1962
/t select          50000      49991         -9
/t usleep          10000      11941       1941
/t nanosleep       10000      11973       1973
/t select          10000       9974        -26
/t usleep           1000       2976       1976
/t nanosleep        1000       2974       1974
/t select           1000        993         -7
/t usleep            900       1968       1068
/t nanosleep         900       1978       1078
/t select            900        966         66
/t usleep            500       1971       1471
/t nanosleep         500       1973       1473
/t select            500        992        492
/t usleep            100       1970       1870
/t nanosleep         100       1979       1879
/t select            100        968        868
/t usleep             10       1972       1962
/t nanosleep          10       1974       1964
/t select             10        993        983
/t usleep              1       1969       1968
/t nanosleep           1       1983       1982
/t select              1        960        959
/t usleep              0        988        988
/t nanosleep           0        961        961
/t select              0          5          5
/t usleep              0        971        971

通过上表可以看出usleep(1000)实际 延时将近3ms。



评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值