實(shí)時(shí)操作系統的任務(wù)調度原因分析
在當前的任務(wù)中,并沒(méi)有關(guān)于就緒表等全局變量的訪(fǎng)問(wèn),當前的任務(wù)也有自己的堆??臻g,我并不知道是否有更高優(yōu)先級的任務(wù)就緒,之所以產(chǎn)生這些疑惑是沒(méi)有搞清楚什么時(shí)候發(fā)生調度,怎么知道需要調度。當前運行的任務(wù),一般而言就是所謂的最高優(yōu)先級的任務(wù),在沒(méi)有訪(fǎng)問(wèn)一系列全局變量的過(guò)程中,內核又是如何知道存在一個(gè)更高優(yōu)先級的任務(wù)被就緒了呢?
一般而言,對于搶占型實(shí)時(shí)內核,一般在同步、或者通信的過(guò)程中會(huì )主動(dòng)的調用調度函數,或者任務(wù)的掛起函數中使用調度函數,其他的函數中并沒(méi)有發(fā)現其他的調度函數,而且這種情況下都是手動(dòng)的調度任務(wù),那么在沒(méi)有這些函數的情況下,實(shí)時(shí)操作系統中內核是如何知道需要調度的呢?
我仔細查找了一些資料,別人總結了一些操作系統發(fā)生調度的原因如下:
(1)正在執行的進(jìn)程執行完畢。這時(shí),如果不選擇新的就緒進(jìn)程執行,將浪費處理機資源。
(2)執行中進(jìn)程自己調用阻塞原語(yǔ)將白己阻塞起來(lái)進(jìn)入睡眠等狀態(tài)。
(3)執行中進(jìn)程調用了P原語(yǔ)操作,從而因資源不足而被阻塞;或調用了v原語(yǔ)操作激活了等待資源的進(jìn)程隊列。
(4)執行中進(jìn)程提出I/O請求后被阻塞。
(5)在分時(shí)系統中時(shí)間片已經(jīng)用完。
(6)在執行完系統調用等系統程序后返回用戶(hù)進(jìn)程時(shí),這時(shí)可看作系統進(jìn)程執行完畢,從而可調度選擇一新的用戶(hù)進(jìn)程執行。
以上都是在可剝奪方式下的引起進(jìn)程調度的原因。在CPU執行方式是可剝奪時(shí).還有
(7)就緒隊列中的某進(jìn)程的優(yōu)先級變得高于當前執行進(jìn)程的優(yōu)先級,從而也將引發(fā)進(jìn)程調度。
我對比了在實(shí)時(shí)操作系統中經(jīng)常使用的調度方式發(fā)現,原因(2)、(3)、(7)是主要的原因,其他的一般在實(shí)時(shí)操作系統中很難找到。但是這還是不能回答什么時(shí)候發(fā)生調度這個(gè)問(wèn)題。
我認為在實(shí)時(shí)操作系統中發(fā)生調度的主要有兩個(gè)部分:
(1)自身需要睡眠等待,必須手動(dòng)的調用調度函數(信息量,或者通信機制)。
(2)發(fā)生中斷過(guò),當執行完中斷服務(wù)函數以后,需要重新調度。
其中原因(2)是我們在分析實(shí)時(shí)操作系統中實(shí)時(shí)性能的主要因素,很多人又會(huì )有很多的疑問(wèn),如果操作系統中很少使用中斷,實(shí)質(zhì)上在實(shí)時(shí)系統中必須存在的一個(gè)中斷就是時(shí)間節拍中斷,這個(gè)中斷的存在就能保證實(shí)時(shí)操作系統的實(shí)時(shí)型。這個(gè)時(shí)間節拍選擇也是設計過(guò)程中必須注意的。我們可以參看uC/OS-II的時(shí)間節拍代碼,其中完成了所有對非任務(wù)掛起的任務(wù)的就緒操作(時(shí)間到期),這時(shí)也就知道了那個(gè)任務(wù)需要我們調度。在其他的中斷服務(wù)函數執行完成以后也就需要那個(gè)任務(wù)需要被執行,進(jìn)而實(shí)現了實(shí)時(shí)操作。
void OSTimeTick (void)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPUstatusregister */
OS_CPU_SR cpu_sr;
#endif
OS_TCB *ptcb;
OSTimeTickHook(); /* Call user definable hook */
#if OS_TIME_GET_SET_EN > 0
OS_ENTER_CRITICAL(); /* Update the 32-bit tick counter */
OSTime++;
OS_EXIT_CRITICAL();
#endif
if (OSRunning == TRUE) {
ptcb = OSTCBList; /* Point at first TCB in TCB list */
while (ptcb->OSTCBPrio != OS_IDLE_PRIO) { /* Go through all TCBs in TCB list */
OS_ENTER_CRITICAL();
if (ptcb->OSTCBDly != 0) { /* Delayed or waiting for event with TO */
if (--ptcb->OSTCBDly == 0) { /* Decrement nbr of ticks to end of delay */
if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) { /* Is task suspended? */
OSRdyGrp |= ptcb->OSTCBBitY; /* No, Make task R-to-R (timed out)*/
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
} else {
/* Yes, Leave 1 tick to prevent ... */
ptcb->OSTCBDly = 1; /* ... loosing the task when the ... */
} /* ... suspension is removed. */
}
}
ptcb = ptcb->OSTCBNext; /* Point at next TCB in TCB list */
OS_EXIT_CRITICAL();
}
}
}
從上面的代碼中我們可以知道每個(gè)任務(wù)都會(huì )被掃描一次,檢測是否能夠就緒,如果能夠就緒就將就緒表中的值設置,這樣也就知道了是否有更高優(yōu)先級的任務(wù)就緒,是否需要調度操作。因為時(shí)間節拍中斷的不斷發(fā)生就能保證最高優(yōu)先級任務(wù)的發(fā)生。因此時(shí)間節拍中斷函數是在實(shí)時(shí)操作系統中非常重要的函數之一。當然任務(wù)之間切換以及在中斷中切換到新的任務(wù)中的切換代碼也是非常重要的,但是這些一般涉及到CPU寄存器的值,需要匯編代碼實(shí)現。
因為中斷完成以后很多的任務(wù)可能因為信號量等信息的釋放已經(jīng)就緒,這時(shí)候必然需要任務(wù)的調度操作,這時(shí)候也就知道了那個(gè)任務(wù)是最高優(yōu)先級的,那個(gè)任務(wù)應該被執行。這時(shí)也就是發(fā)生調度的時(shí)刻。
在UC/OS-II中通常采用關(guān)閉中斷的方式進(jìn)入臨界區,因為關(guān)閉了中斷,所有的中斷服務(wù)函數都不會(huì )被執行,也就不會(huì )發(fā)生任務(wù)的調度。那么只有一個(gè)情況才會(huì )發(fā)生調度,也就是任務(wù)自身需要睡眠,手動(dòng)選擇調度函數,但是在臨界區中不應該發(fā)生睡眠等,因此也就不可能手動(dòng)調度,因此所有發(fā)生調度的可能都被清除了,這樣也就保證了臨界區代碼的安全性。
評論