1、實驗說明:工具
在介紹互斥信號量前,咱們先簡單地描述一下什麼是優先級反轉。使用實時內核心,優先級反轉問題是實時系統中出現得最多的問題。假設任務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的優先級發生了反轉。spa
任務優先級反轉是不容許出現的,由於它可能會形成不可預期的嚴重後果,所以uC/OS-II提供了一種特殊的二值信號量——互斥信號量,它可以順利地解決這種現象。code
(1)任務H和任務M正在等待一個事件發生,處於掛起狀態,任務L正在執行。htm
(2)在某一時刻,任務L請求一個互斥信號量以可以訪問一個共享資源。blog
(3)任務L請求到共享資源的互斥信號量,開始訪問該共享資源。事件
(4)任務H等待的事件發生,因爲任務H的優先級高於任務L的優先級,內核掛起了任務L開始執行任務H。ip
(5)任務H開始執行。資源
(6)任務H也想訪問L如今正在訪問着的共享資源(它想從任務L獲得互斥信號量),爲了儘快地讓任務H請求到互斥信號量,而且在L訪問共享資源過程當中再也不被其餘中等優先級任務打斷,uC/OS-II將任務L的優先級提高到任務H同等高度。get
(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執行。
2、實驗截圖:
3、源代碼下載連接:
連接:https://pan.baidu.com/s/1qZavQpA 密碼:o8p5
4、核心代碼
/* * 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連接: