一、實驗說明:
在介紹互斥訊號量前,我們先簡單地描述一下什麼是優先順序反轉。使用實時核心心,優先順序反轉問題是實時系統中出現得最多的問題。假設任務H優先順序高於任務M,任務M優先順序高於任務L。任務H和任務M處於掛起狀態,等待某一事件發生,任務L正在執行。此時,任務L要使用共享資源。使用共享資源之前,首先必須得到該資源的訊號量。任務L得到了該訊號量,並開始使用該共享資源。由於任務H的優先順序高,它等待的事件到來之後剝奪了任務L的CPU使用權,任務L被掛起,任務H開始執行。執行過程中任務H也要使用那個任務L正在使用著的資源,由於該資源的訊號量還被任務L佔用著,任務H只能進入掛起狀態,等待任務L釋放該訊號量。任務L得以繼續執行。由於任務M的優先順序高於任務L,當任務M等待的事件發生後,任務M剝奪了任務L的CPU使用權並開始執行。處理它該處理的事件,直到處理完之後將CPU控制權還給任務L。任務L接著執行,直到釋放那個共享資源的訊號量。直到此時,由於實時核心知道有個高優先順序的任務(任務H)在等待這個訊號量,核心做任務切換,使任務H得到該訊號量並接著執行。
在這種情況下,任務H優先順序實際上降到了任務L的優先順序水平。因為任務H要等,一直等到任務L釋放佔有的那個共享資源。由於任務M剝奪了任務L的CPU使用權,使任務H的狀況更加惡化,任務M使任務H增加了額外的延遲時間。任務H和任務M的優先順序發生了反轉。
任務優先順序反轉是不允許出現的,因為它可能會造成不可預期的嚴重後果,因此uC/OS-II提供了一種特殊的二值訊號量——互斥訊號量,它能夠順利地解決這種現象。
(1)任務H和任務M正在等待一個事件發生,處於掛起狀態,任務L正在執行。
(2)在某一時刻,任務L請求一個互斥訊號量以能夠訪問一個共享資源。
(3)任務L請求到共享資源的互斥訊號量,開始訪問該共享資源。
(4)任務H等待的事件發生,由於任務H的優先順序高於任務L的優先順序,核心掛起了任務L開始執行任務H。
(5)任務H開始執行。
(6)任務H也想訪問L現在正在訪問著的共享資源(它想從任務L得到互斥訊號量),為了儘快地讓任務H請求到互斥訊號量,並且在L訪問共享資源過程中不再被其他中等優先順序任務打斷,uC/OS-II將任務L的優先順序提升到任務H同等高度。
(7)任務L繼續訪問共享資源,然而它現在是以任務H的優先順序進行的,注意任務H還沒有執行,因為它正在等待任務L釋放互斥訊號量,換句話說,任務H在該互斥訊號量的等待列表中。
(8)任務L完成共享資源的使用,釋放掉互斥訊號量 。uC/OS-II發現任務L的優先順序被提高,因此將任務L的優先順序降低到原來的高度。然後,uC/OS-II將釋放的互斥訊號量分配給正在等待的任務H。
(9)任務H獲得互斥訊號量,開始訪問共享資源。
(10)任務H完成共享資源的使用,釋放掉互斥訊號量。
(11)沒有更高優先順序的任務執行,因此任務H繼續執行。
(12)任務H完成,開始等待一個事件。這時uC/OS-II恢復當任務H或者任務L正在執行時處於就緒態的任務M。
(13)任務M執行。
二、實驗截圖:
三、原始碼下載連結:
連結:https://pan.baidu.com/s/1qZavQpA 密碼:o8p5
四、核心程式碼
/* * Name : main * Description : --- * Author : liu. * * History * -------------------- * Rev : 0.00 * Date : 07/12/2017 * * create. * -------------------- */ /*實驗現象: 開啟串列埠工具putty.exe,終端顯示此時任務AppTask1_task,AppTask2_task和AppTask3_task 的執行狀態,任務AppTask1_task請求到互斥訊號量紅色ARM.LED點亮,任務AppTask2_task運 行過程中藍色ARM.LED閃爍。 備註:當任務AppTask1_task請求互斥態進入就緒態時,之後本應該執行的任務AppTask2_task (藍色ARM.LED閃爍),由於任務AppTask3_task的優先順序被提高(高於任務AppTask2_task), 所以任務AppTask2_task就進入了就緒態(藍色ARM.LED停止閃爍),等待任務AppTask3_task 釋放出訊號量後繼續執行。 */ int main(void) { system_clock.initialize(); //系統時鐘初始化 led.initialize(); //LED初始化 usart6.initialize(115200); //串列埠初始化 key.initialize(); OSInit(); //UCOS初始化 OSTaskCreate(start_task, //建立開始任務 (void*)0, //任務引數 (OS_STK*)&START_TASK_STK[START_STK_SIZE-1], //任務堆疊 START_TASK_PRIO); //任務優先順序 OSStart(); //開啟UCOS }
/* * Name : start_task * Description : --- * Author : liu. * * History * -------------------- * Rev : 0.00 * Date : 07/12/2017 * * create. * -------------------- */ void start_task(void *pdata) { INT8U err; OS_CPU_SR cpu_sr; TaskMutex = OSMutexCreate(0, &err);//建立互斥訊號量 OSStatInit();//初始化統計任務 OS_ENTER_CRITICAL();//關中斷 OSTaskCreate(AppTask1_task,(void*)0,(OS_STK*)&AppTask1_TASK_STK[AppTask1_STK_SIZE-1],AppTask1_TASK_PRIO);//建立AppTask1任務 OSTaskCreate(AppTask2_task,(void*)0,(OS_STK*)&AppTask2_TASK_STK[AppTask2_STK_SIZE-1],AppTask2_TASK_PRIO);//建立AppTask2任務 OSTaskCreate(AppTask3_task,(void*)0,(OS_STK*)&AppTask3_TASK_STK[AppTask3_STK_SIZE-1],AppTask3_TASK_PRIO);//建立AppTask3任務 OSTaskSuspend(OS_PRIO_SELF);//掛起start_task任務 OS_EXIT_CRITICAL();//開中斷 }
/* * Name : AppTask1_task * Description : --- * Author : liu. * * History * -------------------- * Rev : 0.00 * Date : 07/12/2017 * * create. * -------------------- */ void AppTask1_task(void *pdata) { u8 err; while(1){ usart6.printf("\x0c"); //清屏 usart6.printf("\033[1;32;40m"); //設定字型終端為綠色 usart6.printf("\r\n The Task1 is running!\r"); OSTimeDlyHMSM(0,0,1,0); //延時1s usart6.printf("\r\n The Task1 is pending Mutex!\r"); /*等待一個互斥訊號量*/ OSMutexPend(TaskMutex, 0, &err); usart6.printf("\r\n The Task1 has got Mutex!\r"); LED_RED_ON; /*釋放一個互斥訊號量*/ OSMutexPost(TaskMutex); OSTimeDlyHMSM(0,0,1,0); //延時1s LED_RED_OFF; } } /* * Name : AppTask2_task * Description : --- * Author : liu. * * History * -------------------- * Rev : 0.00 * Date : 07/12/2017 * * create. * -------------------- */ void AppTask2_task(void *pdata) { while(1){ usart6.printf("\r\n The Task2 is running!\r"); LED_BLUE_ON; OSTimeDlyHMSM(0,0,0,200); //延時200ms LED_BLUE_OFF; OSTimeDlyHMSM(0,0,0,200); //延時200ms } } /* * Name : AppTask3_task * Description : --- * Author : liu. * * History * -------------------- * Rev : 0.00 * Date : 07/12/2017 * * create. * -------------------- */ void AppTask3_task(void *pdata) { int i; u8 err; while(1){ /*等待一個互斥訊號量*/ OSMutexPend(TaskMutex, 0, &err); usart6.printf("\r\n The Task3 is running!\r"); for(i = 0; i< 2000000; i ++){ OS_Sched(); } /*釋放一個互斥訊號量*/ OSMutexPost(TaskMutex); OSTimeDlyHMSM(0,0,1,0); //延時1s } }
iCore4連結: