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()有有很大的問題
- 在一些平台下不是線程安全,如HP-UX以及Linux
- usleep()會影響信号
- 在很多平台,如HP-UX以及某些Linux下,當參數的值必須小于1 * 1000 * 1000也就是1秒,否則該函數會報錯,并且立即傳回。
- 大部分平台的幫助文檔已經明确說了,該函數是已經被舍棄的函數。
還好,POSIX規範中有一個很好用的函數,nanosleep(),該函數沒有usleep()的這些缺點,它的精度是納秒級。在Solaris的多線程環境下編譯器會自動把usleep()連接配接成nanosleep()。
Linux下短延時推薦使用select函數.