以下轉載自安富萊電子: http://forum.armfly.com/forum.php
調度鎖
調度鎖就是 RTOS 提供的調度器開關函數,如果某個任務調用了調度鎖開關函數,處於調度鎖開和調
度鎖關之間的代碼在執行期間是不會被高優先級的任務搶占的,即任務調度被禁止。這一點要跟臨界段的
作用區分開,調度鎖只是禁止了任務調度,並沒有關閉任何中斷,中斷還是正常執行的。而臨界段進行了
開關中斷操作。
中斷鎖
中斷鎖就是 RTOS 提供的開關中斷函數,FreeRTOS 沒有專門的中斷鎖函數,使用 前一節里面介
紹的中斷服務程序臨界段處理函數就可以實現同樣效果。
任務鎖
簡單的說,為了防止當前任務的執行被其它高優先級的任務打斷而提供的鎖機制就是任務鎖。
FreeRTOS 也沒有專門的任務鎖函數,但是使用 FreeRTOS 現有的功能有兩種實現方法:
通過給調度器加鎖實現
利用 FreeRTOS 的調度鎖功能給調度器加鎖的話,將關閉任務切換功能,從而高優先級任務也就無法
搶占低優先級任務的執行,同時高優先級任務也是無法向低優先級任務切換的。 另外特別注意,調度
鎖只是禁止了調度器工作,並沒有關閉任何中斷。
通過關閉任務切換中斷 PendSV 和系統時鍾節拍中斷 Systick
利用 FreeRTOS 的任務代碼臨界段處理函數就可以關閉 PendSV 中斷和 Systick 中斷。因為進入臨界
段前,操作寄存器 basepri 關閉了所有小於等於宏定義
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 所定義的中斷優先級(實現任務切換功能
的 PendSV 中斷和滴答定時器中斷是最低優先級中斷,所以也是被關閉的),這樣低優先級任務在執
行臨界段代碼期間是不會被高優先級任務打斷的,從而就實現了任務鎖的效果。
FreeRTOS 調度鎖開啟
使用如下函數可以實現 FreeRTOS 的調度鎖開啟:
vTaskSuspendAll()
函數原型:
void vTaskSuspendAll( void );
函數描述:
函數 vTaskSuspendAll 用於實現 FreeRTOS 調度鎖開啟。
使用這個函數要注意以下問題:
1. 調度鎖函數只是禁止了任務調度,並沒有關閉任何中斷。
2. 調度鎖開啟函數 vTaskSuspendAll 和調度鎖關閉函數 xTaskResumeAll 一定要成對使用。
3. 切不可在調度鎖開啟函數 vTaskSuspendAll 和調度鎖關閉函數 xTaskResumeAll 之間調用任何會引起任務切換的 API,比如 vTaskDelayUntil、 vTaskDelay、 xQueueSend 等。
FreeRTOS 調度鎖關閉
使用如下函數可以實現 FreeRTOS 的調度鎖關閉:
xTaskResumeAll ()
函數原型:
BaseType_t xTaskResumeAll(void)
函數描述:
函數 xTaskResumeAll 用於實現 FreeRTOS 調度鎖關閉
調度鎖關閉后,如果需要任務切換,此函數返回 pdTRUE,否則返回 pdFALSE。
使用這個函數要注意以下問題:
1. 調度鎖函數只是禁止了任務調度,並沒有關閉任何中斷。
2. 調度鎖開啟函數 vTaskSuspendAll 和調度鎖關閉函數 xTaskResumeAll 一定要成對使用。
3. 切不可在調度鎖開啟函數 vTaskSuspendAll 和調度鎖關閉函數 xTaskResumeAll 之間調用任何會引起任務切換的 API,比如 vTaskDelayUntil、 vTaskDelay、 xQueueSend 等。
eg:
void vTaskLed1(void *pvParameters) { /* 任務都是一個無限,不能返回 */ while(1) { vTaskSuspendAll(); /* 開啟調度鎖 */ printf("任務vTaskLed1正在運行\r\n"); if(!xTaskResumeAll()) /* 關閉調度鎖,如果需要任務切換,此函數返回pdTRUE,否則返回pdFALSE */ { taskYIELD (); } LED3_ON; /* 阻塞延時,單位ms */ vTaskDelay( 500 ); LED3_OFF; vTaskDelay( 500 ); } }
這里需要注意紅色部分,就是關閉調度鎖的時候,加上了一個if判斷,這個判斷的目的是什么呢?是不是多余的呢?開啟和關閉調度鎖不是像下面這樣就可的嗎:
那為什么官方的demo中有這樣一個判斷?
先看關閉調度鎖返回值的解釋:
如果恢復調度造成了上下文切換,返回pdTRUE,否則返回pdFLASE。這里
要滿足if,證明沒有上下文切換,然后調用taskYIELD(),這個函數是強制上下文轉換:
這也就證明了,如果調用xTaskResumeAll()沒有進行上下文切換,我們將強制進行上下文切換,如果進行了上下文切換,這個if判斷是多余的。官方解釋:
另外需要注意,強制進行上下文切換,不代表本任務中xTaskResumeAll()后面的語句就不執行了,這里led燈的亮滅依舊會執行,(除非有高優先級任務打斷此刻的任務了)只是調度器重新獲得了調度權限,可以在多個任務間進行調度和切換。還有注意調度鎖,不能鎖中斷。
我之前還想,要是在一個低優先級的任務中運行一段不想被高優級打斷的程序時freertos怎么做,現在知道了,調度鎖和臨界段。
實驗效果: