操作延時
一,長延時
1, 忙等待--通過監聽jiffies值得變化
延時1s
unsigned j=jiffies+1;
while(time_before(jiffies , j)){
cpu_relax();//nothing to do;
}
分析:
1》 非搶佔設備上:在循環延時等待期間會整個鎖住處理器;調度器從來不會搶佔運行在內核空間的進程;
2》 搶佔設備上: 如果沒有擁有鎖的話,處理器還可以運行其他進程;但是忙等待任然有些浪費,特別是不能禁止中斷,如果禁止中斷,jiffies 值不會變化,機器就會永遠的等待,除非按下關機鍵切斷電源;
3》在低負荷設備上運行良好:每次延時1s,每次系統調用都能立即執行,兩次系統調用之間的時間極短;
4》在高負荷設備上運行分兩種情況:
a,非搶佔設備:如上述缺點,在延時等待期間會整個鎖住處理器,所以每個系統調用的延時爲1s,但是每次系統調用都不會立即執行,在兩次系統調用之間有較長的時候,而且隨負荷增加越來越明顯,這是因爲多任務處理器時間是共享的,在兩次系統調用之後,調度器會把處理器時間分配給其他進程;
b,搶佔設備:如上述特點,由於在延時期間可能被中斷所以延時時長可能增加,兩次系統調用之間的時間不是進程調度的唯一選擇所以兩次系統調用之間的時間可能會縮短;
2,在忙等待的基礎上讓出處理器;
unsigned long j=jiffies+1;
while(time_before(jiffies,j)){
schedule();
}
分析:
理論上性能好點,但是也沒有實質性的優化;
1》在低負荷設備上運行:由於schedule()僅僅讓出處理器,但是等待進程還在運行隊列中,所以在沒有其他進程的時候,延時循環進程剛讓出處理器緊接着又被調度,所以實際上在延時等待的時候還是一直使用處理器,只要運行就會耗電等消耗資源;
2》在高負荷設備上:
a,非搶佔設備:這個過程和上述忙等待中高負荷--非搶佔設備運行過程一致;
b,搶佔設備: 這個和上述忙等待高負荷--搶佔設備運行過程基本一直,但是這個在延時等待過程中增加了進程調度的時間,當延時時間到期時,由於進程可能不會被立即調度執行,所以延時時間可能會延長,而且延長的時間隨設備符合增加越來越明顯;
綜上兩種延時方案(監聽jiffies忙等待,讓出處理器)整體性能都不太好;所以內核爲驅動程序提供了第三種延時方案;
3,超時等待
a,unsigned long wait_event_interruptible_timeout(wait_queue_head_t wait ,condition , long jiffies);
b,unsigned long wait_event_timeout(wait_queue_head_t wait , condition , long jiffies);
返回值 等待時間到期或延期都返回0,等待過程被中斷返回剩餘時長,用無符號unsigned long 來表示剩餘時長(即始終中斷次數);
上述api都是在某個隊列上等待某個事件;有時需要一種特殊情況,就是不在任何隊列上等待任何事件的延時,內核提供了這樣的特殊情況即就是直接使用上述api等底層實現原理(schedule_timeout(unsigned jiffies)),在調度之前一定要修改進程狀態,否則進程一直在運行隊列所以和上述讓出處理器方案一樣:
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(jiffies);
分析:超時等待過程進程不在運行隊列,所以不會佔用處理器,所以不受搶佔與非搶佔影響,基本也不受符合高低的影響,但是有一點,就是在等待過程中延時時間已到期進程可能不會立即被調度,所以延時時間可能延長延長時間就是等待被調度的時間,但是這都不是問題,因爲在實際使用中設備基本都強調的是至少延時多長時間;
二,短延時
有時要求延時時長非常短,內核提供了下面幾個api來滿足短延時;
a,void mdelay(usinged long millisecs);
b,void udelay(usigned long usecs);
c,void ndelay(usinged long nsecs);
重點需要注意的是上述單個函數都是忙等待;
d,void msleep(unsigned int millisecs);//延時的毫秒數;
e,unsigned long msleep_interruptible(unsigned int millisecs);//可中斷延時的毫秒數;
f,void ssleep(unsigned seconds);//延時的秒數;