一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Qsys與uC/OS-II學(xué)習(xí)筆記5:任務(wù)切換

 戴維圖書(shū)館 2016-11-01

 

Qsys與uC/OS-II學(xué)習(xí)筆記5:任務(wù)切換
         上個(gè)筆記提到調(diào)用任務(wù)延時(shí)函數(shù)后,系統(tǒng)將會(huì)進(jìn)行任務(wù)切換,否則當(dāng)前運(yùn)行任務(wù)就會(huì)一直霸占著CPU的使用權(quán)。那么這個(gè)任務(wù)延時(shí)函數(shù)中到底有什么奧秘?調(diào)用它為什么能夠讓任務(wù)切換自如?這個(gè)筆記咱就要揭開(kāi)uC/OS-II的一大設(shè)計(jì)精髓——任務(wù)切換。
         特權(quán)同學(xué)并非軟件工程或是計(jì)算機(jī)科班出身,還真沒(méi)學(xué)過(guò)什么操作系統(tǒng),對(duì)于CPU內(nèi)部架構(gòu)和工作機(jī)制的理解和認(rèn)識(shí)完全靠自身的實(shí)踐、摸索加一些教科書(shū)的研讀。對(duì)于一些概念的闡述或許不夠?qū)I(yè),如果有些偏差也非常歡迎大家提出來(lái)加以糾正,但是我想這些“草根”式的圖文或許多少能夠幫助大家快速的理解和認(rèn)識(shí)一些工作機(jī)理,但愿“八九不離十”應(yīng)該是形容這種狀態(tài)比較合適的詞匯吧。其實(shí)如果能起到這樣的效果,那么對(duì)這些文章而言也就足夠。畢竟一板一眼、中規(guī)中矩的教科書(shū)我們看得太多了,真的是有些審美疲勞了。
         因?yàn)橐f(shuō)任務(wù)調(diào)度的機(jī)理,那么我們不得不先把幾乎所有嵌入式處理器相關(guān)的書(shū)籍中都會(huì)提及的中斷概念再提一下。雖然講中斷的書(shū)滿(mǎn)大街都是,但是我想像圖1這樣一個(gè)簡(jiǎn)單示意圖就能夠把中斷說(shuō)清楚的還真不多(怎么有點(diǎn)“王婆賣(mài)瓜自賣(mài)自夸”的嫌疑,臉紅中~~)。一個(gè)“裸奔”的CPU軟件,無(wú)非就是一個(gè)main函數(shù)里面while(1)中包辦所有功能,偶爾來(lái)個(gè)中斷響應(yīng)一些實(shí)時(shí)性要求較高的處理,僅此而已。那么,很顯然,中斷響應(yīng)時(shí)有一個(gè)脫離當(dāng)前main函數(shù)的舉動(dòng)發(fā)生,想要讓中斷響應(yīng)前后CPU回到原有的main函數(shù)執(zhí)行狀態(tài),則必須有一些額外的工作要干,第3和6步的出棧、入棧便是。這個(gè)示意圖中,大家需要明白,當(dāng)某個(gè)函數(shù)或某些指令占用CPU時(shí),意味著CPU中的寄存器存儲(chǔ)著和當(dāng)前處理狀態(tài)相關(guān)的各種中間數(shù)據(jù)信息;同樣的道理,當(dāng)中斷函數(shù)占有CPU數(shù)據(jù)時(shí),CPU中的寄存器存儲(chǔ)著和中斷函數(shù)相關(guān)的各種中間數(shù)據(jù)。堆棧是專(zhuān)門(mén)開(kāi)辟的一片存儲(chǔ)空間,用于和CPU寄存器相映射。一個(gè)在main函數(shù)中運(yùn)行著的程序(包括在它的子函數(shù)中運(yùn)行),如果被一個(gè)中斷信號(hào)打斷后去執(zhí)行中斷處理,最后返回,這樣一個(gè)過(guò)程,發(fā)生了以下一些事情:
1.       應(yīng)用程序(即Main函數(shù))中執(zhí)行某條指令,此時(shí)應(yīng)用程序控制CPU的使用權(quán),表現(xiàn)為占有CPU寄存器。
2.       一個(gè)中斷源產(chǎn)生,應(yīng)用程序停下了CPU的使用。
3.       應(yīng)用程序停下來(lái)那一刻的CPU寄存器內(nèi)容被copy到堆棧中,即我們稱(chēng)之為入棧操作。
4.       程序轉(zhuǎn)到中斷處理函數(shù)執(zhí)行,表現(xiàn)為即將到來(lái)的下一時(shí)刻中斷處理函數(shù)占有CPU使用權(quán)。
5.       中斷處理函數(shù)擁有CPU使用權(quán),表現(xiàn)為占有CPU寄存器,直到中斷處理函數(shù)執(zhí)行完成。
6.       CPU寄存器恢復(fù)執(zhí)行入棧操作前的狀態(tài),即從堆棧中copy之前入棧的信息,我們稱(chēng)之為出棧。
7.       應(yīng)用程序回到中斷前的下一條指令開(kāi)始執(zhí)行,雖然經(jīng)過(guò)2-6步的“意外事件”,但是除了應(yīng)用程序比預(yù)期延時(shí)了一小段時(shí)間執(zhí)行外,好像這個(gè)“意外事件”沒(méi)有發(fā)生過(guò)一樣。
圖1
         再來(lái)看uC/OS-II中的任務(wù)切換是如何實(shí)現(xiàn)的,應(yīng)該說(shuō),和傳統(tǒng)CPU的中斷機(jī)制有著異曲同工之妙。說(shuō)白了,uC/OS-II其實(shí)也是假借中斷之名偷梁換柱般完成了任務(wù)的切換。因?yàn)閡C/OS-II中的每個(gè)task都好比“裸奔”著的軟件程序中的main函數(shù),他們都有機(jī)會(huì)獨(dú)立的占用CPU的使用權(quán)。Task的寫(xiě)法通常有兩種:
void user_task(void* pdata)
{
 while (1)
 {
    //用戶(hù)代碼
 }
}
或者
void user_task(void* pdata)
{
 //用戶(hù)代碼
 OSTaskDel(OS_PRIO_SELF); //刪除當(dāng)前任務(wù)
}
         前者我們已經(jīng)接觸過(guò),在用戶(hù)代碼的最后我們通常也會(huì)加上任務(wù)延時(shí)函數(shù),讓出CPU的控制權(quán)。而后者相當(dāng)于一次性完成的任務(wù),執(zhí)行過(guò)一次該任務(wù)后,自我刪除,從此銷(xiāo)聲匿跡,除非該任務(wù)在其他任務(wù)函數(shù)中被重新建立恢復(fù)。
OSTaskDel();函數(shù)
INT8U         OSTaskDel               (INT8U            prio);
         當(dāng)任務(wù)創(chuàng)建并由OSStart()函數(shù)啟動(dòng)后,要么處于運(yùn)行態(tài)(同一時(shí)刻有且只有一個(gè)運(yùn)行態(tài)的任務(wù)),要么處于就緒態(tài),如果處于某個(gè)正在運(yùn)行的任務(wù)使用OSTaskDel()函數(shù)刪除了該任務(wù)本身或者其他任務(wù)(空閑任務(wù)OSTaskIdle()是唯一不能被刪除的任務(wù)),那么被刪除的任務(wù)并不是從存儲(chǔ)代碼的程序中物理消失了,這段代碼還在,只不過(guò)它已經(jīng)不在任務(wù)切換優(yōu)先級(jí)列表中了,以后的任務(wù)切換中不會(huì)考慮運(yùn)行該任務(wù),我們說(shuō)這種狀態(tài)叫做休眠態(tài),如果要從休眠態(tài)喚醒到就緒態(tài),則需要重新創(chuàng)建該函數(shù)。
OSTaskIdle()函數(shù)
         空閑任務(wù)是在OSInit();函數(shù)中被建立的,看這個(gè)函數(shù)的具體內(nèi)容,發(fā)現(xiàn)它其實(shí)并沒(méi)有干什么大事,無(wú)非是在那里“消磨時(shí)間”,也的確是這樣。但uC/OS-II中必須建立空閑函數(shù),而且它的優(yōu)先級(jí)一定是最低的,至于為什么,我們接下來(lái)先講講任務(wù)切換的機(jī)理,然后大家很容易就能明白的。
void OS_TaskIdle (void *p_arg)
{
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR cpu_sr = 0;
#endif
    (void)p_arg;                                 /* Prevent compiler warning for not using 'p_arg'     */
    for (;;) {
        OS_ENTER_CRITICAL();
        OSIdleCtr++;
        OS_EXIT_CRITICAL();
        OSTaskIdleHook();                        /* Call user definable HOOK                           */
    }
}
         如圖2所示,這便是任務(wù)切換的大體流程。和中斷很相似,這里假設(shè)task1要切換到task2,task1中一定會(huì)調(diào)用任務(wù)延時(shí)函數(shù)(上一個(gè)筆記已經(jīng)提到,這是任務(wù)切換的必要條件),咱還是簡(jiǎn)單的12345把它說(shuō)明白:
1.       Task1擁有CPU的控制權(quán),當(dāng)前CPU寄存器存儲(chǔ)著和task1當(dāng)前執(zhí)行指令相關(guān)的信息。
2.       Task1調(diào)用了任務(wù)延時(shí)函數(shù)。
3.       CPU寄存器的數(shù)據(jù)信息被copy到了堆棧中,即入棧,這個(gè)堆棧是task1獨(dú)有的,圣神不可侵犯。
4.       把Task2獨(dú)有的堆棧數(shù)據(jù)信息paste到CPU寄存器中,即出棧,這是要恢復(fù)task2在上一次擁有CPU控制權(quán)的最后一條執(zhí)行指令留下的現(xiàn)場(chǎng)。當(dāng)然也可能task2之前未曾擁有過(guò)CPU控制權(quán),沒(méi)關(guān)系,那么默認(rèn)這個(gè)堆棧是應(yīng)該是個(gè)空的。
5.       模擬產(chǎn)生了一個(gè)軟中斷源產(chǎn)生,任務(wù)延時(shí)函數(shù)被中斷,停止繼續(xù)執(zhí)行。
6.       模擬中斷處理函數(shù),大概這個(gè)函數(shù)中什么都不做,為的是有一個(gè)中斷返回的動(dòng)作(還真有點(diǎn)買(mǎi)櫝還珠的味道)。
7.       中斷返回時(shí),當(dāng)前的CPU寄存器是task2的工作現(xiàn)場(chǎng),那么這意味著task2已經(jīng)擁有了CPU的控制權(quán)。怎么樣?真得是被“偷梁換柱”了,CPU已經(jīng)從task1的while(1)里面被“俘虜”到了task2中。至此,一次任務(wù)切換完成。
圖2
         大家可以好好消化一下,其實(shí)任務(wù)的切換還真的不是傳說(shuō)中那么神奇。到這里,還是沒(méi)有把任務(wù)延時(shí)函數(shù)的神秘面紗揭開(kāi),沒(méi)關(guān)系,一個(gè)一個(gè)來(lái),咱要各個(gè)擊破,每個(gè)知識(shí)點(diǎn)都吃透了才行。
         我們先給出任務(wù)延時(shí)的一個(gè)最基本函數(shù)OSTimeDly()的程序,注意看該函數(shù)的最后調(diào)用了OS_Sched()函數(shù),該函數(shù)便是CPU任務(wù)切換的“罪魁禍?zhǔn)住保闷嫘膹?qiáng)的朋友可不能放過(guò)它。
void OSTimeDly (INT16U ticks)
{
    INT8U      y;
#if OS_CRITICAL_METHOD == 3                      /* Allocate storage for CPU status register           */
    OS_CPU_SR cpu_sr = 0;
#endif
    if (OSIntNesting > 0) {                      /* See if trying to call from an    ISR                  */
        return;
    }
    if (ticks > 0) {                             /* 0 means no delay!                                  */
        OS_ENTER_CRITICAL();
        y = OSTCBCur->OSTCBY;        /* Delay current task                                 */
        OSRdyTbl[y] &= ~OSTCBCur->OSTCBBitX;
        if (OSRdyTbl[y] == 0) {
            OSRdyGrp &= ~OSTCBCur->OSTCBBitY;
        }
        OSTCBCur->OSTCBDly = ticks;              /* Load ticks in TCB                                  */
        OS_EXIT_CRITICAL();
        OS_Sched();                              /* Find next task to run!                             */
    }
}
         OS_Sched()函數(shù)完成任務(wù)級(jí)的調(diào)度,該函數(shù)完成了前一個(gè)任務(wù)CPU寄存器的入棧和后一個(gè)任務(wù)CPU寄存器的出棧,并且在最后做了一次“模擬”中斷返回的操作,這個(gè)操作是由OS_TASK_SW()函數(shù)里完成的。
void OS_Sched (void)
{
#if OS_CRITICAL_METHOD == 3                            /* Allocate storage for CPU status register     */
    OS_CPU_SR cpu_sr = 0;
#endif
    OS_ENTER_CRITICAL();
    if (OSIntNesting == 0) {                           /* Schedule only if all ISRs done and ...       */
        if (OSLockNesting == 0) {                      /* ... scheduler is not locked                  */
            OS_SchedNew();
            if (OSPrioHighRdy != OSPrioCur) {          /* No Ctx Sw if current task is highest rdy     */
                OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
#if OS_TASK_PROFILE_EN > 0
                OSTCBHighRdy->OSTCBCtxSwCtr++;         /* Inc. # of context switches to this task      */
#endif
                OSCtxSwCtr++;                          /* Increment context switch counter             */
                OS_TASK_SW();                          /* Perform a context switch                     */
            }
        }
    }
    OS_EXIT_CRITICAL();
}
         函數(shù)void OSCtxSw(void);咱還真無(wú)法右鍵open打開(kāi),通常不是用C語(yǔ)言寫(xiě)的,而是用匯編來(lái)完成這個(gè)操作。
         再回到 OSTaskIdle()函數(shù),試想想如果系統(tǒng)中只有兩個(gè)用戶(hù)任務(wù)task1和task2,如果他們都調(diào)用任務(wù)延時(shí)函數(shù),那么模擬中斷返回后系統(tǒng)應(yīng)該到哪里繼續(xù)執(zhí)行程序呢?不得而知,或許程序就要跑飛了,基于此,OSTaskIdle()函數(shù)就有存在的必要了,雖然它好像不干什么事,但至少它能保證系統(tǒng)在沒(méi)有task可執(zhí)行的時(shí)候處于一個(gè)可控的狀態(tài)中。除此以外,OSTaskIdle()函數(shù)中還做了一件或許大家多少還是有些在意的CPU使用率的計(jì)算,它是通過(guò)計(jì)算空閑時(shí)間來(lái)推斷每秒鐘CPU的使用率的。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多

    国产又黄又猛又粗又爽的片| 亚洲国产精品久久网午夜| 国产精品免费不卡视频| 在线观看日韩欧美综合黄片| 色综合伊人天天综合网中文| 国产丝袜美女诱惑一区二区| 一本色道久久综合狠狠躁| 正在播放国产又粗又长| 国产传媒欧美日韩成人精品| 亚洲中文字幕日韩在线| 国产精品久久久久久久久久久痴汉 | 午夜精品成年人免费视频| 日本欧美在线一区二区三区| 91偷拍裸体一区二区三区| 亚洲午夜福利视频在线| 日韩女优视频国产一区| 最新69国产精品视频| 国产福利一区二区三区四区| 91日韩欧美在线视频| 欧美精品久久99九九| 免费福利午夜在线观看| 视频一区二区 国产精品| 黄片免费在线观看日韩| 国产又粗又长又大高潮视频| av在线免费观看在线免费观看| 国产真人无遮挡免费视频一区| 日韩精品区欧美在线一区| 欧美日韩视频中文字幕| 亚洲精品一区三区三区| 中文字幕日韩无套内射| 欧美日韩精品综合在线| 肥白女人日韩中文视频 | 午夜视频成人在线观看| 欧美一级片日韩一级片| 黄片免费播放一区二区| 久久99亚洲小姐精品综合| 91精品国自产拍老熟女露脸| av在线免费观看在线免费观看| 中国一区二区三区不卡| 夫妻性生活真人动作视频| 欧美精品久久一二三区|