首先感謝如下兩篇的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。