- RT-Thread內核實現與應用開發實戰指南:基于STM32
- 劉火良 楊森
- 2057字
- 2019-01-21 10:02:21
第2章
裸機系統與多線程系統
在真正開始動手編寫RTOS之前,我們先來講解一下單片機編程中的裸機系統和多線程系統。
2.1 裸機系統
裸機系統通常分成輪詢系統和前后臺系統,有關這兩者的具體實現方式請看下面的講解。
2.1.1 輪詢系統
輪詢系統即在裸機編程過程中,先初始化相關的硬件,然后讓主程序在一個死循環里面不斷循環,順序地做各種事情,大概的偽代碼參見代碼清單2-1。輪詢系統是一種非常簡單的軟件結構,通常只適用于那些只需要順序執行代碼且不需要外部事件來驅動就能完成的操作。在代碼清單2-1中,如果只是實現LED翻轉、串口輸出、液晶顯示等操作,那么使用輪詢系統將會非常完美。但是,如果加入了按鍵操作等需要檢測外部信號的事件,或者用來模擬緊急報警,那么整個系統的實時響應能力就不會那么好了。假設DoSomething3是按鍵掃描操作,當外部按鍵被按下,相當于產生一個警報,這個時候,需要立刻響應,并做緊急處理,而這時程序剛好執行到DoSomething1,并且DoSomething1執行的時間會比較久,久到按鍵釋放之后都沒有執行完畢,那么當執行到DoSomething3時就會丟失一次事件。由此可見輪詢系統只適合用于順序執行的功能代碼,當有外部事件驅動時,實時性就會降低。
代碼清單2-1 輪詢系統偽代碼
1 int main(void) 2 { 3 /* 硬件相關初始化 */ 4 HardWareInit(); 5 6 /* 無限循環 */ 7 for (; ; ) { 8 /* 處理事件1 */ 9 DoSomething1(); 10 11 /* 處理事件2 */ 12 DoSomething2(); 13 14 /* 處理事件3 */ 15 DoSomething3(); 16 } 17 }
2.1.2 前后臺系統
相較于輪詢系統,前后臺系統是在輪詢系統的基礎上加入了中斷。外部事件的響應在中斷里面完成,對事件的處理還是回到輪詢系統中完成。在這里我們稱中斷為“前臺”, main()函數里面的無限循環稱為“后臺”,大概的偽代碼參見代碼清單2-2。
代碼清單2-2 前后臺系統偽代碼
1 int flag1 = 0; 2 int flag2 = 0; 3 int flag3 = 0; 4 5 int main(void) 6 { 7 /* 硬件相關初始化 */ 8 HardWareInit(); 9 10 /* 無限循環 */ 11 for (; ; ) { 12 if (flag1) { 13 /* 處理事件1 */ 14 DoSomething1(); 15 } 16 17 if (flag2) { 18 /* 處理事件2 */ 19 DoSomething2(); 20 } 21 22 if (flag3) { 23 /* 處理事件3 */ 24 DoSomething3(); 25 } 26 } 27 } 28 29 void ISR1(void) 30 { 31 /* 置位標志位 */ 32 flag1 = 1; 33 /* 如果事件處理時間很短,則在中斷里面處理; 34 如果事件處理時間比較長,則回到后臺處理 */ 35 DoSomething1(); 36 } 37 38 void ISR2(void) 39 { 40 /* 置位標志位 */ 41 flag2 = 1; 42 43 /* 如果事件處理時間很短,則在中斷里面處理; 44 如果事件處理時間比較長,則回到后臺處理 */ 45 DoSomething2(); 46 } 47 48 void ISR3(void) 49 { 50 /* 置位標志位 */ 51 flag3 = 1; 52 53 /* 如果事件處理時間很短,則在中斷里面處理; 54 如果事件處理時間比較長,則回到后臺處理 */ 55 DoSomething3(); 56 }
在順序執行后臺程序時,如果有中斷產生,那么中斷會打斷后臺程序的正常執行流,轉而去執行中斷服務程序,在中斷服務程序里面標記事件。如果要處理的事件很簡短,則可在中斷服務程序里面處理,如果要處理的事件比較繁雜,則返回后臺程序中處理。雖然事件的響應和處理被分開了,但是事件的處理還是在后臺中順序執行的,相比輪詢系統,前后臺系統確保了事件不會丟失,再加上中斷具有可嵌套的功能,這可以大大提高程序的實時響應能力。在大多數中小型項目中,前后臺系統運用得好,堪比操作系統的效果。
2.2 多線程系統
相比前后臺系統,多線程系統的事件響應也是在中斷中完成的,但事件的處理是在線程中完成的。在多線程系統中,線程與中斷一樣,也具有優先級,優先級高的線程會被優先執行。當一個緊急事件在中斷中被標記之后,如果事件對應的線程的優先級足夠高,就會立刻得到響應。相比前后臺系統,多線程系統的實時性又被提高了。多線程系統大概的偽代碼參見代碼清單2-3。
代碼清單2-3 多線程系統偽代碼
1 int flag1 = 0; 2 int flag2 = 0; 3 int flag3 = 0; 4 5 int main(void) 6 { 7 /* 硬件相關初始化 */ 8 HardWareInit(); 9 10 /* OS初始化 */ 11 RTOSInit(); 12 13 /* OS啟動,開始多線程調度,不再返回 */ 14 RTOSStart(); 15 } 16 17 void ISR1(void) 18 { 19 /* 置位標志位 */ 20 flag1 = 1; 21 } 22 23 void ISR2(void) 24 { 25 /* 置位標志位 */ 26 flag2 = 2; 27 } 28 29 void ISR3(void) 30 { 31 /* 置位標志位 */ 32 flag3 = 1; 33 } 34 35 void DoSomething1(void) 36 { 37 /* 無限循環,不能返回 */ 38 for (; ; ) { 39 /* 線程實體 */ 40 if (flag1) { 41 42 } 43 } 44 } 45 46 void DoSomething2(void) 47 { 48 /* 無限循環,不能返回 */ 49 for (; ; ) { 50 /* 線程實體 */ 51 if (flag2) { 52 53 } 54 } 55 } 56 57 void DoSomething3(void) 58 { 59 /* 無限循環,不能返回 */ 60 for (; ; ) { 61 /* 線程實體 */ 62 if (flag3) { 63 64 } 65 } 66 }
相比前后臺系統中后臺順序執行的程序主體,在多線程系統中,根據程序的功能,我們把這個程序主體分割成一個個獨立的、無限循環且不能返回的小程序,這個小程序我們稱之為“線程”。每個線程都是獨立的、互不干擾的,且具備自身的優先級,它由操作系統調度管理。加入操作系統后,我們在編程時不需要再精心設計程序的執行流,不用擔心每個功能模塊之間是否存在干擾。加入了操作系統,我們的編程反而變得簡單了。整個系統帶來的額外開銷就是操作系統占據的少量FLASH和RAM。現如今,單片機的FLASH和RAM容量越來越大,完全足以支撐RTOS的開銷。
無論是輪詢系統、前后臺系統還是多線程系統,不能單純地評定孰優孰劣,它們是不同時代的產物,在各自的領域有相當大的應用價值,只有合適的才是最好的。有關這3個軟件模型的區別如表2-1所示。
表2-1 輪詢系統、前后臺系統和多線程系統軟件模型的區別

- GraphQL學習指南
- 構建移動網站與APP:HTML 5移動開發入門與實戰(跨平臺移動開發叢書)
- 程序員面試算法寶典
- 運用后端技術處理業務邏輯(藍橋杯軟件大賽培訓教材-Java方向)
- MySQL入門很輕松(微課超值版)
- 大話Java:程序設計從入門到精通
- 持續集成與持續交付實戰:用Jenkins、Travis CI和CircleCI構建和發布大規模高質量軟件
- Hack與HHVM權威指南
- Python Linux系統管理與自動化運維
- VMware vSphere 5.5 Cookbook
- Laravel 5.x Cookbook
- 流暢的Python
- 語義Web編程
- Flask Web開發實戰:入門、進階與原理解析
- 你也能看得懂的Python算法書