天天看点

关于短延迟 SLEEP USLEEP NANOSLEEP SELECT

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

继续阅读