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
#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()有有很大的问题
- 在一些平台下不是线程安全,如HP-UX以及Linux
- usleep()会影响信号
- 在很多平台,如HP-UX以及某些Linux下,当参数的值必须小于1 * 1000 * 1000也就是1秒,否则该函数会报错,并且立即返回。
- 大部分平台的帮助文档已经明确说了,该函数是已经被舍弃的函数。
还好,POSIX规范中有一个很好用的函数,nanosleep(),该函数没有usleep()的这些缺点,它的精度是纳秒级。在Solaris的多线程环境下编译器会自动把usleep()连接成nanosleep()。
Linux下短延时推荐使用select函数.