Linux平臺延時之sleep、usleep、nanosleep、select比較
1、sleep的精度是秒
2、usleep的精度是微妙,不精確
3、select的精度是微妙,精確
struct?timevaldelay;
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%。
無論是WinCE還是Linux操作系統,應用線程的運行總是涉及到兩個基本的參數:一個是系統分配給線程的時間片,一個是系統調度的時間間隔。Linux和WinCE下這兩個參數有所不同,如下表所示:
WinCE | 嵌入式Linux | |
??線程的運行時間片 | 100ms | 10ms |
??系統調度間隔 | 1ms | 10ms |
Linux 高精確的時序(sleep, usleep,nanosleep)
原文地址:http://www.linux.org.tw/CLDP/MiniHOWTO/prog/IO-Port-Programming/IO-Port-Programming-4.html
4. 高精確的時序
4.1 延遲時間
首先, 我會說不保證你在使用者模式 (user-mode) 中執行的行程 (process) 能夠精確地控制時序因為 Linux 是個多工的作業環境. 你在執行中的行程 (process) 隨時會因為各種原因被暫停大約 10 毫秒到數秒 (在系統負荷非常高的時候). 然而, 對於大多數使用 I/O 埠的應用而言, 這個延遲時間實際上算不了什麼. 要縮短延遲時間, 你得使用函式 nice 將你在執行中的行程 (process ) 設定成高優先權(請參考 nice(2) 使用說明文件) 或使用即時排程法 (real-time scheduling) (請看下面).
如果你想獲得比在一般使用者模式 (user-mode) 中執行的行程 (process) 還要精確的時序, 有一些方法可以讓你在使用者模式 (user-mode) 中做到 `即時' 排程的支援. Linux 2.x 版本的核心中有軟體方式的即時排程支援; 詳細的說明請參考 sched_setscheduler(2) 使用說明文件. 有一個特殊的核心支援硬體的即時排程; 詳細的資訊請參考網頁 http://luz.cs.nmt.edu/~rtlinux/
休息中 (Sleeping) : sleep() 與 usleep()
現在, 讓我們開始較簡單的時序函式呼叫. 想要延遲數秒的時間, 最佳的方法大概是使用函式 sleep() . 想要延遲至少數十毫秒的時間 (10 ms 似乎已是最短的延遲時間了), 函式 usleep() 應該可以使用. 這些函式是讓出 CPU 的使用權給其他想要執行的行程 (processes) (``自己休息去了''), 所以沒有浪費掉 CPU 的時間. 細節請參考 sleep(3) 與 usleep(3) 的說明文件.
如果讓出 CPU 的使用權因而使得時間延遲了大約 50 毫秒 (這取決於處理器與機器的速度, 以及系統的負荷), 就浪費掉 CPU 太多的時間, 因為 Linux 的排程器 (scheduler) (單就 x86 架構而言) 在將控制權發還給你的行程 (process) 之前通常至少要花費 10-30 毫秒的時間. 因此, 短時間的延遲, 使用函式 usleep(3) 所得到的延遲結果通常會大於你在參數所指定的值, 大約至少有 10 ms.
nanosleep()
在 Linux 2.0.x 一系列的核心發行版本中, 有一個新的系統呼叫 (system call), nanosleep() (請參考 nanosleep(2) 的說明文件), 他讓你能夠休息或延遲一個短的時間 (數微秒或更多).
如果延遲的時間 <= 2 ms, 若(且唯若)你執行中的行程 (process) 設定了軟體的即時排程 (就是使用函式 tt/sched_setscheduler()/), 呼叫函式 nanosleep() 時不是使用一個忙碌迴圈來延遲時間; 就是會像函式 usleep() 一樣讓出 CPU 的使用權休息去了.
這個忙碌迴圈使用函式 udelay() (一個驅動程式常會用到的核心內部的函式) 來達成, 並且使用 BogoMips 值 (BogoMips 可以準確量測這類忙碌迴圈的速度) 來計算迴圈延遲的時間長度. 其如何動作的細節請參考 /usr/include/asm/delay.h).
使用 I/O 埠來延遲時間
另一個延遲數微秒的方法是使用 I/O 埠. 就是從埠位址 0x80 輸入或輸出任何 byte 的資料 (請參考前面) 等待的時間應該幾乎只要 1 微秒這要看你的處理器的型別與速度. 如果要延遲數微秒的時間你可以將這個動作多做幾次. 在任何標準的機器上輸出資料到該埠位址應該不會有不良的後果纔對 (而且有些核心的設備驅動程式也在使用他). {in|out}[bw]_p() 等函式就是使用這個方法來產生時間延遲的 (請參考檔案 asm/io.h).
實際上, 一個使用到埠位址範圍為 0-0x3ff 的 I/O 埠指令幾乎只要 1 微秒的時間, 所以如果你要如此做, 例如, 直接使用並列埠, 只要加上幾個 inb() 函式從該埠位址範圍讀入 byte 的資料即可.
使用組合語言來延遲時間
如果你知道執行程式所在機器的處理器型別與時鐘速度, 你可以執行某些組合語言指令以便獲得較短的延遲時間 (但是記住, 你在執行中的行程 (process) 隨時會被暫停, 所以有時延遲的時間會比實際長). 如下面的表格所示, 內部處理器的速度決定了所要使用的時鐘周期數; 如, 一個 50 MHz 的處理器 (486DX-50 或 486DX2-50), 一個時鐘周期要花費 1/50000000 秒 (=200 奈秒).
指令????????? i386 時鐘周期數?????? i486 時鐘周期數
nop?????????????????? 3?????????????????? 1
xchg %ax,%ax????????? 3?????????????????? 3
or %ax,%ax??????????? 2?????????????????? 1
mov %ax,%ax?????????? 2?????????????????? 1
add %ax,0???????????? 2?????????????????? 1
(對不起, 我不知道 Pentiums的資料, 或許與 i486 接近吧. 我無法在 i386 的資料上找到只花費一個時鐘周期的指令. 如果能夠就請使用花費一個時鐘周期的指令, 要不然就使用管線技術的新式處理器也是可以縮短時間的.)
上面的表格中指令 nop 與 xchg 應該不會有不良的後果. 指令最後可能會改變旗號暫存器的內容, 但是這沒關係因為 gcc 會處理. 指令 nop 是個好的選擇.
想要在你的程式中使用到這些指令, 你得使用 asm("instruction"). 指令的語法就如同上面表格的用法; 如果你想要在單一的asm() 敘述中使用多個指令, 可以使用分號將他們隔開. 例如, asm("nop ; nop ; nop ; nop") 會執行四個 nop 指令, 在 i486 或 Pentium 處理器中會延遲四個時鐘周期(或是 i386 會延遲 12 個時鐘周期).
gcc 會將 asm() 翻譯成單行組合語言程式碼,所以不會有呼叫函式的負荷.
在 Intel x86 架構中不可能有比一個時鐘周期還短的時間延遲.
在 Pentiums 處理器上使用函式 rdtsc
對於 Pentiums 處理器而言, 你可以使用下面的 C 語言程式碼來取得自從上次重新開機到現在經過了多少個時鐘周期:
??extern __inline__ unsigned long long int rdtsc()
?? {
????unsigned long long int x;
????__asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
????return x;
?? }
你可以詢問參考此值以便延遲你想要的時鐘周期數.
4.2 時間的量測
想要時間精確到一秒鐘, 使用函式 time() 或許是最簡單的方法. 想要時間更精確, 函式 gettimeofday() 大約可以精確到微秒 (但是如前所述會受到 CPU 排程的影響). 至於 Pentiums 處理器, 使用上面的程式碼片斷就可以精確到一個時鐘周期.
如果你要你執行中的行程 (process) 在一段時間到了之後能夠被通知 (get a signal), 你得使用函式 setitimer() 或 alarm() . 細節請參考函式的使用說明文件.
--------------------------------------------------
再論精確延時(usleep,nanosleep,select)
/*
???????make:? gcc -o test_sleeptest_sleep.c
*/
/*???????#include? "comm_main.h"*/
#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;
? intret = 0;
?unsigned int nDelay = 0;??????? /*usec */
?fd_set rfds;
?struct timeval tv;
? intfd = 1;
? inti = 0;
?struct timespec req;
?unsigned int delay[20] =
??? {500000, 100000, 50000, 10000, 1000, 900, 500, 100, 10, 1, 0 };
? intnReduce = 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 <= 0)
???????break;
?????nDelay = delay;
?????/*????? 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
????????
??????????????? 由此可以得出如下結論,在 linux2.4 下:
??????????????????????? 1、支持usleep,nanosleep,select
??????????????????????? 2、select 的 精確度為 10毫秒。在10毫秒以上很精確
?????????????? ?????????3、usleep,nanosleep? 很不精確
??????????????? 同樣,通過其它測試程序能得出如下結論:
??????????????????????? sleep? 可以在多線程中使用,只阻塞本線程,不影響所屬進程中的其它線程
???????????????????????????????????????
???????????????????????
???????????????
我只有以上3種測試環境,有其它測試環境的幫我在其它環境下測試一下,將分析結果貼出來。
測試程序在之后發上來
什么場合下會用到pthread_yield
pthread_yield 使當前的線程自動放棄剩余的CPU時間從而讓另一個線程運行,但個人感覺 usleep 足以完成這個功能,到底 pthread_yield 用在什么場合呢?有人在實戰項目中用過或者見過使用 pthread_yield 的么
pthread_yield() causes the calling threadto relinquish the CPU. The thread is placed at the end of the run queue for itsstatic priority and another thread is scheduled to run.
個人覺得可以用pthread_yield來減少一些低優先級的實時線程對CPU的消耗,不過需要注意的是,pthread_yield并不能代替usleep(),例如隊列檢查中,如果發現隊列空時采用yield放棄時間片,也仍會導致CPU 100%。
參考鏈接:與windows中的Sleep(0)等價的pthread_yield
網上有用函數pthread_yield()可能出現的問題。
參考鏈接:Mutex takes a long while to unlock
========================
我在以前的一個項目中使用過pthread_yield。
pthread_yield可以用于實現同步。當在一個父進程中,開辟了2個子線程,而只有這2個子線程都執行完了之后,父進程才能進行下一步的工作。這個時候,在父進程開啟這兩個子線程之后,需要調用pthread_yield讓父進程等待這2個子線程執行完。
本文由 貴州做網站公司 整理發布,部分圖文來源于互聯網,如有侵權,請聯系我們刪除,謝謝!
網絡推廣與網站優化公司(網絡優化與推廣專家)作為數字營銷領域的核心服務提供方,其價值在于通過技術手段與策略規劃幫助企業提升線上曝光度、用戶轉化率及品牌影響力。這...
在當今數字化時代,公司網站已成為企業展示形象、傳遞信息和開展業務的重要平臺。然而,對于許多公司來說,網站建設的價格是一個關鍵考量因素。本文將圍繞“公司網站建設價...
在當今的數字化時代,企業網站已成為企業展示形象、吸引客戶和開展業務的重要平臺。然而,對于許多中小企業來說,高昂的網站建設費用可能會成為其發展的瓶頸。幸運的是,隨...
怎么成為淘寶金牌賣家?獎牌賣家的基本條件有以下以下幾點:信用度最少一個站,15克黃油消費者購買基本保障最新計劃,店面21秒大于等于183天;5克白糖消保,這個現在已經不用擔心了以前淘寶天貓已經打開了全網第一消保計劃;開店43秒,這是人力物力不能整體控制的,除非直接買個淘寶網店。如何申請淘寶金牌賣家?遞交申請淘寶奧運金牌淘寶賣家的常見方法見下文淘寶店要繳交淘寶網保證金,開店把時間必須在183天以上,...
彩虹島瓦爾哈拉怎么走?1瓦爾哈拉殺死前兩個怪手然后在傳送門下殺死兩個流星錘打開門。其他怪物不用打,2不用殺怪物,可以去4和4,也沒有怪物可以殺。關鍵是從4傳送門到3(去3就是從4到5,然后一條直線到3)和6把圣女貞德全部干掉,傳送門就開了。注意,你可以去一個從4底只有一個圣女貞德的封閉的地方。其他的奇怪可以忽略。彩虹島瓦爾基里在哪里?瓦哈拉,是嗎?你在做第二份工作嗎?瓦哈拉在太空的頂端。彩虹島魔法...
pcie1x是什么插口?PCIE x1插槽是為主板設計的擴展功能卡接口。如帶PCIE X1接口的聲卡、千兆網卡、擴展USB3.0接口卡、電視卡等。主板(英文:Motherboard,縮寫為Mobo,別名:motherboard,system board,logic board,motherboard,backplan主板各個插槽的名稱及與各線連接方式?1是VGA接口(連接到顯示器)2是DVI接口(...