?簡 介?
Azure RTOS ThreadX 是 Microsoft 提供的高級工業(yè)級實時操作系統(tǒng) (RTOS)。它是專門為深度嵌入式實時 IoT 應用程序設計的。Azure RTOS ThreadX 提供高級計劃、通信、同步、計時器、內(nèi)存管理和中斷管理功能。此外,Azure RTOS ThreadX 具有許多高級功能,包括 picokernel 體系結構、preemption-threshold 計劃、event-chaining、執(zhí)行分析、性能指標和系統(tǒng)事件跟蹤。Azure RTOS ThreadX 非常易于使用,適用于要求極其苛刻的嵌入式應用程序。Azure RTOS ThreadX 在各種產(chǎn)品(包括消費者設備、醫(yī)療電子設備和工業(yè)控制設備)上的部署次數(shù)已達數(shù)十億次。
具體的介紹和用戶指南可以參考:
https://docs.microsoft.com/zh-cn/azure/rtos/threadx/
在前文描述移植基本內(nèi)核的基礎上,本文描述了如何基于MM32F3270系列MCU結合Azure RTOS ThreadX應用搶占任務preemption-threshold的使用,引導用戶理解Azure RTOS ThreadX搶占任務preemption-threshold功能。
表 1 適用系列型號
系列 |
芯片型號 |
開發(fā)板 |
MM32F3270 |
MM32F3273G9P |
EVB-F3270 |
?
? ?1
? ?移植應用的準備
1.1?? 硬件開發(fā)板的準備
該移植過程中應用的開發(fā)板為MM32的EVB-F3270,板載MM32F3273G9P。
EVB-F3270 (MM32F3273G9P)的簡要參數(shù):
?Arm Cortex-M3 內(nèi)核
?板載 MM32F3273G9P(LQFP144)
? ?4 x Key、4 x LED
?I2S Speaker
?TF-Card
?Ethernet PHY
?
1.2? 軟件的準備
? ?庫函數(shù)和例程(Lib Samples)
該移植過程中應用的 Firmware 分別為 MM32F3270 庫函數(shù)和例程,下載地址:
https://www.mindmotion.com.cn/products/mm32mcu/mm32f/mm32f_mainstream/mm32f3270/
? ?Azure RTOS ThreadX(源碼)
ThreadX 的源代碼已經(jīng)開放,我們可以從 ThreadX 公共源代碼存儲庫獲取 Azure RTOS ThreadX,網(wǎng)址為:
https://github.com/azure-rtos/threadx/
具體的商用使用條件參考Azure的許可證說明:
https://www.microsoft.com/en-us/legal/intellectualproperty/tech-licensing/programs?msclkid=f7ab4ff3afa011ec90a79366a52034fa&activetab=pivot1:primaryr11
Microsoft publishes the Azure RTOS source code to GitHub. No license is required to install and use the software for internal development, testing, and evaluation purposes. A license is required to distribute or sell components and devices unless using Azure RTOS licensed hardware.
Azure RTOS 何時需要許可證?
Microsoft 將 Azure RTOS 源代碼發(fā)布到 GitHub。安裝和使用該軟件進行內(nèi)部開發(fā)、測試和評估無需許可證。分發(fā)或銷售組件和設備需要許可證,除非使用 Azure RTOS 許可的硬件。
ThreadX 安裝
可以通過將 GitHub 存儲庫克隆到本地計算機來安裝 ThreadX。下面是用于在 PC 上創(chuàng)建 ThreadX 存儲庫的克隆的典型語法。
shell復制
git clone https://github.com/azure-rtos/threadx
或者,也可以使用 GitHub 主頁上的“下載”按鈕來下載存儲庫的副本。
下載后的倉庫代碼目錄列表如下:
? ?Azure RTOS ThreadX(源碼)支持的開發(fā)環(huán)境
ThreadX 內(nèi)核提供好了各種主流硬件平臺和軟件平臺的移植文件,以Cortex_M3為例,可以支持以下六種開發(fā)環(huán)境:
本次移植過程使用Azure RTOS原有的sample_threadx.c Samples為例子,稍作修改,演示了搶占任務的功能與應用。
?
? ?2
? ?Threadx 搶占任務的應用
該章節(jié)介紹了搶占任務應用實現(xiàn)的背景與應用目的,該演示程序可在MM32F3273G9P的EVB-F3270上運行。
此示例在文件 main_preemption_demo.c中實現(xiàn),旨在說明如何在嵌入式多線程環(huán)境中使用搶占任務,實現(xiàn)任務之間的優(yōu)先級切換與搶占。
2.1? 任務優(yōu)先級與切換的知識
? ?2.1.1? 線程優(yōu)先級
ThreadX 在創(chuàng)建線程時通過分配表示其“優(yōu)先級”的數(shù)值來確定線程的重要性。
ThreadX 的最大優(yōu)先級數(shù)可在 32 到 1024(增量為 32)之間進行配置。
因此:
TX_MAX_PRIORITIES的宏定義設置的數(shù)值必須是32的整數(shù)倍:
#define TX_MAX_PRIORITIES 32
實際的最大優(yōu)先級數(shù)由 TX_MAX_PRIORITIES 常數(shù)在 ThreadX 庫的編譯過程中確定。設置更多優(yōu)先級并不會顯著增加處理開銷。但是,每個包含 32 個優(yōu)先級的組額外需要 128 字節(jié)的 RAM 進行管理。例如,32 個優(yōu)先級需要 128 字節(jié)的 RAM,64 個優(yōu)先級需要 256 字節(jié)的 RAM,而 96 個優(yōu)先級需要 384 字節(jié)的 RAM。
默認情況下,ThreadX 具有 32 個優(yōu)先級,范圍從優(yōu)先級 0 到優(yōu)先級 31。數(shù)值越小,優(yōu)先級越高。因此,優(yōu)先級 0 表示最高優(yōu)先級,而優(yōu)先級 (TX_MAX_PRIORITIES-1) 表示最低優(yōu)先級。
ThreadX沒有空閑任務,如果大家創(chuàng)建空閑任務,需要將其設置為最低優(yōu)先級。
通過協(xié)作調度或時間切片,多個線程可以具有相同的優(yōu)先級。
此外,線程優(yōu)先級還可以在運行時更改。
? ?2.1.2? 線程切換調度
ThreadX 根據(jù)線程的優(yōu)先級來調度線程。優(yōu)先級最高的就緒線程最先執(zhí)行。如果有多個具有相同優(yōu)先級的線程準備就緒,則按照先進先出 (FIFO) 的方式執(zhí)行。
ThreadX操作系統(tǒng)支持三種調度方式:搶占式調度,時間切片調度和輪詢式調度。
在一般的應用中,主要是搶占式調度和時間切片調度,輪詢式調度用到的很少。
?輪循任務調度
ThreadX 支持通過輪循調度處理具有相同優(yōu)先級的多個線程。此過程通過以協(xié)作方式調用 tx_thread_relinquish 來實現(xiàn)。此服務為相同優(yōu)先級的所有其他就緒線程提供了在 tx_thread_relinquish 調用方再次執(zhí)行之前執(zhí)行的機會。
?時間切片任務調度
“時間切片”是輪循調度的另一種形式。時間片指定線程在不放棄處理器的情況下可以執(zhí)行的最大計時器時鐘周期數(shù)(計時器中斷)。在 ThreadX 中,時間切片按每個線程提供。線程的時間片在創(chuàng)建時分配,可在運行時修改。當時間片過期時,具有相同優(yōu)先級的所有其他就緒線程有機會在時間切片線程重新執(zhí)行之前執(zhí)行。
當線程掛起、放棄、執(zhí)行導致?lián)屨嫉?ThreadX 服務調用或自身經(jīng)過時間切片后,該線程將獲得一個新的線程時間片。
當時間切片的線程被搶占時,該線程將在其剩余的時間片內(nèi)比具有相同優(yōu)先級的其他就緒線程更早恢復執(zhí)行。
?搶占式任務調度
搶占任務調度是為了支持優(yōu)先級更高的線程而暫時中斷正在執(zhí)行的線程的過程。每個任務都有不同的優(yōu)先級,任務會一直運行直到被高優(yōu)先級任務搶占或者遇到阻塞式的API函數(shù)。
此過程對正在執(zhí)行的線程不可見。當更高優(yōu)先級的線程完成時,控制權將轉交回發(fā)生搶占的確切位置。這是實時系統(tǒng)中一項非常重要的功能,因為該功能有助于快速響應重要的應用程序事件。
盡管搶占是一項非常重要的功能,但也可能導致各種問題,包括資源不足、開銷過大和優(yōu)先級反轉。為了緩解搶占的一些固有問題,ThreadX 提供了一個獨特的高級功能,名為搶占閾值 (Preemption-threshold)。
搶占閾值允許線程指定禁用搶占的優(yōu)先級上限。優(yōu)先級高于上限的線程仍可以執(zhí)行搶占,但不允許優(yōu)先級低于上限的線程執(zhí)行搶占。
例如,假設優(yōu)先級為 20 的線程只與一組優(yōu)先級介于 15 到 20 之間的線程進行交互。在其關鍵部分中,優(yōu)先級為 20 的線程可將其搶占式閥值設置為 15,從而防止該線程和與之交互的所有線程發(fā)生搶占。這仍允許(優(yōu)先級介于 0和 14 之間)真正重要的線程在其關鍵部分處理中搶占此線程的資源,這會使處理的響應速度更快。
當然,仍有可能通過將其搶占式閥值設置為 0 來為線程禁用所有搶占。此外,可以在運行時更改搶占閾值。
?備注:
使用搶占閾值會禁用指定線程的時間切片。
? ?優(yōu)先級繼承
ThreadX 還支持其互斥服務內(nèi)的可選優(yōu)先級繼承。優(yōu)先級繼承允許低優(yōu)先級線程暫時假設正在等待歸較低優(yōu)先級線程所有的互斥的高優(yōu)先級線程的優(yōu)先級。借助此功能,應用程序可以消除中間優(yōu)先級線程的搶占,從而避免出現(xiàn)不確定的優(yōu)先級倒置。當然,也可以使用“搶占式閥值”獲得類似的結果。
? ?2.1.3? 搶占式任務調度
任務優(yōu)先級需要解決的問題:
?輪循任務調度
選擇線程優(yōu)先級是多線程處理最重要的方面之一。有時很容易根據(jù)感知的線程重要性概念來分配優(yōu)先級,而不是確定運行時到底需要什么。濫用線程優(yōu)先級會導致其他線程資源枯竭、產(chǎn)生優(yōu)先級反轉、減少處理帶寬,致使應用程序出現(xiàn)難以理解的運行時行為。
如前所述,ThreadX 提供基于優(yōu)先級的搶占式調度算法。優(yōu)先級較低的線程只能在沒有更高優(yōu)先級的線程可以執(zhí)行時才會執(zhí)行。如果優(yōu)先級較高的線程始終準備就緒,則不會執(zhí)行優(yōu)先級較低的線程。這種情況稱為線程資源不足。
大多數(shù)線程資源不足的問題都是在調試初期檢測到的,可通過確保優(yōu)先級較高的線程不會連續(xù)執(zhí)行來解決。另外,還可以在應用程序中添加此邏輯,以便逐漸提高資源不足的線程的優(yōu)先級,直到有機會執(zhí)行這些線程。
與線程優(yōu)先級相關的另一個缺陷是“優(yōu)先級倒置”。當優(yōu)先級較高的線程由于優(yōu)先級較低的線程占用其所需資源而掛起時,將會發(fā)生優(yōu)先級倒置。當然,在某些情況下,有必要讓兩個優(yōu)先級不同的線程共享一個公用資源。如果這些線程是唯一處于活動狀態(tài)的線程,優(yōu)先級倒置時間就與低優(yōu)先級線程占用資源的時間息息相關。這種情況既具有確定性又非常正常。不過,如果在這種優(yōu)先級反轉的情況,中等優(yōu)先級的線程變?yōu)榛顒訝顟B(tài),優(yōu)先級反轉時間就不再確定,并且可能導致應用程序失敗。
主要有三種不同的方法可防止 ThreadX 中出現(xiàn)不確定的優(yōu)先級反轉。
?首先,在設計應用程序優(yōu)先級選擇和運行時行為時,可以采用能夠防止出現(xiàn)優(yōu)先級反轉問題的方式。
?其次,優(yōu)先級較低的線程可以利用搶占閾值來阻止中等優(yōu)先級線程在其與優(yōu)先級較高的線程共享資源時執(zhí)行搶占。
?最后,使用 ThreadX 互斥對象保護系統(tǒng)資源的線程可以利用可選的互斥優(yōu)先級繼承來消除不確定的優(yōu)先級反轉。
?優(yōu)先級開銷
要減少多線程處理開銷,最容易被忽視的一種方法是減少上下文切換的次數(shù)。如前所述,當優(yōu)先級較高的線程執(zhí)行優(yōu)先于正在執(zhí)行的線程時,則會發(fā)生上下文切換。值得一提的是,在發(fā)生外部事件(例如中斷)和執(zhí)行線程發(fā)出服務調用時,優(yōu)先級較高的線程可能變?yōu)榫途w狀態(tài)。
為了說明線程優(yōu)先級對上下文切換開銷的影響,假設有一個包含三個線程的環(huán)境,這些線程分別命名為 thread_1、thread_2 和 thread_3。進一步假定所有線程都處于等待消息的掛起狀態(tài)。當 thread_1 收到消息后,立即將其轉發(fā)給 thread_2。隨后,thread_2 將此消息轉發(fā)給 thread_3。Thread_3 只是丟棄此消息。每個線程處理其消息后,則會返回并等待另一個消息。
執(zhí)行這三個線程所需的處理存在很大的差異,具體取決于其優(yōu)先級。如果所有線程都具有相同優(yōu)先級,則會在執(zhí)行每個線程之前發(fā)生一次上下文切換。當每個線程在空消息隊列中掛起時,將會發(fā)生上下文切換。
但是,如果 thread_2 的優(yōu)先級高于 thread_1,thread_3 的優(yōu)先級高于 thread_2,上下文切換的次數(shù)將增加一倍。這是因為當其檢測到優(yōu)先級更高的線程現(xiàn)已準備就緒時,會在 tx_queue_send 服務中執(zhí)行另一次上下文切換。
ThreadX 搶占閾值機制可以避免出現(xiàn)這些額外的上下文切換,并且仍支持前面提到的優(yōu)先級選擇。這是一項重要的功能,因為該功能允許在調度期間使用多個線程優(yōu)先級,同時避免在線程執(zhí)行期間出現(xiàn)一些不需要的上下文切換。
這里僅對搶占式調度進行說明。
運行條件:
?創(chuàng)建 3 個任務 Task1,Task2 和 Task3。
?Task1 的優(yōu)先級為 1,Task2 的優(yōu)先級為 2,Task3 的優(yōu)先級為 3。
沒有使用搶占式任務調度,Task1首先開始運行,此時雖然Task2 就緒,只能在等任務1 完全空閑下來或完成任務;Task2 任然在運行,此時雖然Task3也就緒了,同樣需要等任務2空閑下來或者完成任務,才能轉成運行態(tài),執(zhí)行程序運行。
而使用任務搶占式調度方式,運行過程變?yōu)椋?/p>
A. 任務 Task1 在運行中,運行過程中由于 Task2 就緒(A點),在搶占式調度器的作用下任務 Task2 搶占Task1 的執(zhí)行。Task2 進入到運行態(tài),Task1 由運行態(tài)進入到就緒態(tài)。
B. 任務 Task2 在運行中,運行過程中由于 Task3 就緒(B點),在搶占式調度器的作用下任務 Task3 搶占 Task2的執(zhí)行。Task3 進入到運行態(tài),Task2 由運行態(tài)進入到就緒態(tài)。
C. 任務 Task3 運行過程中調用了阻塞式 API 函數(shù)(C點),比如 tx_thread_sleep,任務 Task3 被掛起,在搶占式調度器的作用下查找到下一個要執(zhí)行的最高優(yōu)先級任務是 Task2,任務 Task2 由就緒態(tài)進入到運行態(tài)。
D. 任務 Task2 運行完成(完成時結束任務2的搶占)前,任務3的阻塞或Sleep時間已經(jīng)結束。下一一步繼續(xù)執(zhí)行的任務是 Task3,任務 Task3完成后,解除本次搶占。任務1由就緒態(tài)進入到運行態(tài),直到運行完成。
2.2? Azure Threadx 任務搶占的相關函數(shù)
tx_thread_preemption_change 更改應用程序線程的搶占閾值
UINT?tx_thread_preemption_change(
????TX_THREAD?*thread_ptr,
????UINT?new_threshold,?
????UINT?*old_threshold);
?
函數(shù)說明
此服務更改指定線程的搶占閾值。搶占閾值阻止指定線程被等于或小于搶占閾值的線程搶占。
?備注:
使用搶占閾值會禁用指定線程的時間切片。
?參數(shù)
?thread_ptr:指向以前創(chuàng)建的應用程序線程的指針。
?new_threshold:新的搶占閾值優(yōu)先級(0 至 TX_MAX_PRIORITIES-1)。
?old_threshold:指向恢復為上一個搶占閾值的位置的指針。
返回值
?TX_SUCCESS:(0X00) 成功更改搶占閾值。
?TX_THREAD_ERROR:(0X0E) 應用程序線程指針無效。
?TX_THRESH_ERROR:(0x18) 指定的新?lián)屨奸撝凳菬o效的線程優(yōu)先級(值不介于 0 到 TX_MAX_PRIORITIES-1 之間)或大于(優(yōu)先級更低)當前線程優(yōu)先級。
?TX_PTR_ERROR:(0x03) 指向之前的搶占閾值存儲位置的指針無效。
?NX_CALLER_ERROR:(0x13) 此服務的調用方無效。
具體函數(shù)的中文說明可以參考:
https://docs.microsoft.com/zh-cn/azure/rtos/threadx/chapter4
具體函數(shù)的英文說明可以參考:
https://docs.microsoft.com/en-us/azure/rtos/threadx/threadx-smp/chapter4#tx_event_flags_set
示例
TX_THREAD?my_thread;
UINT?my_old_threshold;
UINT?status;
/*?Disable?all?preemption?of?the?specified?thread.?The
current?preemption-threshold?is?returned?in
"my_old_threshold".?Assume?that?"my_thread"?has
already?been?created.?*/
status?=?tx_thread_preemption_change(&my_thread,
????0,?&my_old_threshold);
/*?If?status?equals?TX_SUCCESS,?the?application?thread?is
non-preemptable?by?another?thread.?Note?that?ISRs?are
not?prevented?by?preemption?disabling.?*/
2.3? 搶占任務的應用演示
? ?2.3.1? 工程目錄的建立
打開目標工程文件夾“MM32F3270Project”:
移除原有樣例.c 文件sample_threadx.c:
參考sample_threadx.c建立main_preemption_demo.c文件,并添加到工程項目中。
該Demo程序還用到了Led和阻塞時延時,因此還需添加led.c和delay.c。
特別要注意的是需要在led.c中配置USE_SYSTICK_DELAY 為 0。
#define USE_SYSTICK_DELAY 0
? ?2.3.2? 創(chuàng)建搶占任務示例
舉一個極端點的例子:修改搶占任務閾值為0,以確保不被其他任務搶占。
創(chuàng)建一個待使用的搶占任務,并在任務中修改搶占任務閾值。
void????thread_5_entry(ULONG?thread_input)
{
????UINT????status;
????ULONG???actual_flags;
????UINT????old_threshold;
????UINT????i=10;
????/*?This?thread?simply?waits?for?an?event?in?a?forever?loop.??*/
????while(1)?{
????????//?set?preemption?to?0(the?highest,?equal?to?close?the?thread?task?interrupt.
????????status?=?tx_thread_preemption_change(&thread_5,?THREAD5_PREEMPTION_THRESHOLD_NEW,?&old_threshold);
????????if(status?==?TX_SUCCESS)
????????{
????????????//these?code?show?how?the?tx_thread_preemption_change?affect
????????????//user?can?add?code?which?can?not?be?interruptted?by?other?thread
????????????while(i--){
????????????????LED1_TOGGLE();
????????????????DELAY_Ms(100);
????????????}
????????????i=10;
????????????//restore?preemption
????????????tx_thread_preemption_change(&thread_5,?THREAD5_PREEMPTION_THRESHOLD,?&old_threshold);
????????}
????????tx_thread_sleep(100);
????????/*?Increment?the?thread?counter.??*/
????????thread_5_counter++;
????????/*?Wait?for?event?flag?0.??*/
????????status?=??tx_event_flags_get(&event_flags_0,?0x1,?TX_OR_CLEAR,
?????????????????????????????????????&actual_flags,?TX_WAIT_FOREVER);
????????/*?Check?status.??*/
????????if?((status?!=?TX_SUCCESS)?||?(actual_flags?!=?0x1))
????????????break;
????}
}
?
? ?3
? ?Threadx 的搶占任務應用實現(xiàn)與調試
3.1? 代碼實現(xiàn)
下載調試默認會運行到main()函數(shù),如下為全部實現(xiàn)的代碼。
Demo演示代碼
/*?This?is?a?small?demo?of?the?high-performance?ThreadX?kernel.??It?includes?examples?of?six
???threads?of?different?priorities,?using?a?message?queue,?semaphore,?and?an?event?flags?group.??*/
#include?"tx_api.h"
#include?"delay.h"
#include?"led.h"
#define?DEMO_STACK_SIZE?????????????????1024
#define?THREAD0_PRIORITY????????????????????1
#define?THREAD0_PREEMPTION_THRESHOLD????????1
#define?THREAD5_PRIORITY????????????????????4
#define?THREAD5_PREEMPTION_THRESHOLD????????4
#define?THREAD5_PREEMPTION_THRESHOLD_NEW????0
/*?Define?the?ThreadX?object?control?blocks...??*/
TX_THREAD???????????????thread_0;
TX_THREAD???????????????thread_5;
TX_EVENT_FLAGS_GROUP????event_flags_0;
/*?Define?the?counters?used?in?the?demo?application...??*/
ULONG???????????????????thread_0_counter;
ULONG???????????????????thread_5_counter;
/*?Define?the?thread?stacks.??*/
UCHAR???????????????????thread_0_stack[DEMO_STACK_SIZE];
UCHAR???????????????????thread_5_stack[DEMO_STACK_SIZE];
/*?Define?thread?prototypes.??*/
void????thread_0_entry(ULONG?thread_input);
void????thread_5_entry(ULONG?thread_input);
/*?Define?main?entry?point.??*/
int?main()
{
????LED_Init();
????DELAY_Init();?//can?not?use?systick
????/*?Enter?the?ThreadX?kernel.??*/
????tx_kernel_enter();
}
/*?Define?what?the?initial?system?looks?like.??*/
void????tx_application_define(void*?first_unused_memory)
{
????/*?Create?the?main?thread.??*/
????tx_thread_create(
????&thread_0,?
????"thread?0",?
????thread_0_entry,?
????0,
????thread_0_stack,?
????DEMO_STACK_SIZE,
????THREAD0_PRIORITY,?
????THREAD0_PREEMPTION_THRESHOLD,?
????TX_NO_TIME_SLICE,?
????TX_AUTO_START);
????/*?Create?thread?5.??This?thread?simply?pends?on?an?event?flag?which?will?be?set
???????by?thread_0.??*/
????tx_thread_create(
????&thread_5,?
????"thread?5",?
????thread_5_entry,?
????5,
????thread_5_stack,?
????DEMO_STACK_SIZE,
????THREAD5_PRIORITY,?
????THREAD5_PREEMPTION_THRESHOLD,?
????TX_NO_TIME_SLICE,?
????TX_AUTO_START);
????/*?Create?the?event?flags?group?used?by?threads?0?and?5.??*/
????tx_event_flags_create(&event_flags_0,?"event?flags?0");
}
/*?Define?the?test?threads.??*/
void????thread_0_entry(ULONG?thread_input)
{
????UINT????status;
????/*?This?thread?simply?sits?in?while-forever-sleep?loop.??*/
????while(1)?{
????????/*?Increment?the?thread?counter.??*/
????????thread_0_counter++;
????????/*?Sleep?for?10?ticks.??*/
????????tx_thread_sleep(10);
????????/*?Set?event?flag?0?to?wakeup?thread?5.??*/
????????status?=??tx_event_flags_set(&event_flags_0,?0x1,?TX_OR);
????????/*?Check?status.??*/
????????if?(status?!=?TX_SUCCESS)
????????????break;
????}
}
void????thread_5_entry(ULONG?thread_input)
{
????UINT????status;
????ULONG???actual_flags;
????UINT????old_threshold;
????UINT????i=10;
????/*?This?thread?simply?waits?for?an?event?in?a?forever?loop.??*/
????while(1)?{
????????//?set?preemption?to?0(the?highest,?equal?to?close?the?thread?task?interrupt.
????????status?=?tx_thread_preemption_change(&thread_5,?THREAD5_PREEMPTION_THRESHOLD_NEW,?&old_threshold);
????????if(status?==?TX_SUCCESS)
????????{
????????????//these?code?show?how?the?tx_thread_preemption_change?affect
????????????//user?can?add?code?which?can?not?be?interruptted?by?other?thread
????????????while(i--){
????????????????LED1_TOGGLE();
????????????????DELAY_Ms(100);
????????????}
????????????i=10;
????????????//restore?preemption
????????????tx_thread_preemption_change(&thread_5,?THREAD5_PREEMPTION_THRESHOLD,?&old_threshold);
????????}
????????tx_thread_sleep(100);
????????/*?Increment?the?thread?counter.??*/
????????thread_5_counter++;
????????/*?Wait?for?event?flag?0.??*/
????????status?=??tx_event_flags_get(&event_flags_0,?0x1,?TX_OR_CLEAR,
?????????????????????????????????????&actual_flags,?TX_WAIT_FOREVER);
????????/*?Check?status.??*/
????????if?((status?!=?TX_SUCCESS)?||?(actual_flags?!=?0x1))
????????????break;
????}
}
?
3.2? 下載與調試
進入調試模式,可以看到接收搶占任務中閃燈程序運行時,其他高優(yōu)先級的任務不能從就緒態(tài)轉為運行態(tài),Demo演示成功。
該demo示例,建立了2個線程,程序執(zhí)行一個發(fā)送事件標志,另外一個線程接收事件標志,實現(xiàn)執(zhí)行Task Counter與發(fā)送&接收的Message Counter的累加。
全速運行后,可以看到相關的數(shù)值在變化:
但由于任務5中有運行長時間的搶占任務LED0 Toggle的動作,由thread_5_counter于thread_0_counter的巨大差值可以看出:該搶占任務導致Thread0中的發(fā)送到Thread5的事件標志,很多未被接收。從而成功的演示的搶占任務的特性。
?
? ?4
? ?小結
Azure RTOS ThreadX 的使用搶占任務可以方便實現(xiàn)任務優(yōu)先級切換,避免的任務優(yōu)先級的缺陷,結合MM32F3270的強大性能,可以實現(xiàn)Azure RTOS的強大的功能。
?
評論
查看更多