1裸機與RTOS的理解
首先這里只針對單核CPU架構(gòu)的芯片展開討論,大部分是MCU吧,而多核CPU的討論相對比較復雜,暫不涉及~
玩RTOS的朋友都知道,裸機與OS的最大區(qū)別就是實現(xiàn)多任務(wù)的并發(fā),其實你說裸機就不能實現(xiàn)任務(wù)的并發(fā)嗎 ? 這個需要看所站的角度吧,只是說RTOS并發(fā)的粒度可以更加細,因為把裸機的任務(wù)拆分成多塊運行,其實也是一種并發(fā)方式。
從宏觀上雖然RTOS的每個任務(wù)都是在并發(fā)執(zhí)行,其實微觀上還是一條一條指令在順序執(zhí)行著,如下圖所示:
而對于目前主流的RTOS,如UCOS或者FreeRTOS,所實現(xiàn)的都是多任務(wù),更多的是一種多線程的并發(fā)執(zhí)行而非多進程,所以對應(yīng)到Linux平臺上稱他們?yōu)閠hread。
2并發(fā)帶來的問題
并發(fā)的好處就是能夠在更細的粒度來盡可能的提高CPU的利用率,這里不能說使用了多線程就一定能提高,這與你所設(shè)計的任務(wù)劃分和處理有著直接的關(guān)系,只能說
多線程相比裸機更有這個能力。
而任何事物都有其利弊,多個任務(wù)在沒有同步處理的情況下,任務(wù)之間是無序運行的,無序也就意味著狀態(tài)的多樣性和復雜度。
當然bug菌這里所說的無序是一個相對的過程,比如對于CPU而言,它就是順序的去執(zhí)行一條一條的指令,所以在這個層面它是有序的、確定的。
而把過程放大,比如執(zhí)行一條C語言語句,一般它是由多條匯編指令組成,對于目前的搶占式內(nèi)核,在一段時間內(nèi)其多個任務(wù)就有可能指令交替執(zhí)行,當這些指令都去操作同一塊內(nèi)存,那么內(nèi)存的最終結(jié)果由于順序不同而不同,最終難以確定。
狀態(tài)的不確定就有可能造成異常行為,也就是大家經(jīng)常遇到的:"怎么跑著跑著就有問題,還沒啥規(guī)律~","這段代碼怎么看也沒問題呀~"
所以對比看來RTOS確實會帶來編程上的難度~
3臨界區(qū)
既然有難度,我們就要解決,把不確定性部分通過一些手段來變得確定,而造成這些不確定因素的動力是什么呢?是中斷~
bug菌一直覺得,其實對于裸機而言,如果把中斷服務(wù)函數(shù)看成一個更高優(yōu)先級的搶占式任務(wù),其實裸機主任務(wù)與中斷任務(wù)就形成了一種兩任務(wù)的并發(fā),所以中斷與任務(wù)之間也是有共享問題需要類似處理的。
為了解決這些不確定因素,我們只需要在這段代碼區(qū)域限制中斷的發(fā)生即可,這一段區(qū)域就是臨界區(qū),說得直白點 : 關(guān)中斷與開中斷。
1ENTER_CRITICAL();//進入臨界區(qū) 2 3//臨界區(qū)代碼 4 5EXIT_CRITICAL();//退出臨界區(qū)
4臨界區(qū)嵌套
臨界區(qū)的使用沒啥可說的,但是在你的代碼中怎么加臨界區(qū)確實一門技巧,可是說很多3~5年的工程師也并不一定處理得好,本文暫不展開,后面bug菌整理以后再分享給大家,今天只聊聊臨界區(qū)嵌套使用的問題,畢竟很多朋友在這里掉過坑~
參考偽代碼:
1/*********************************************
2 * Function: Fuction1
3 * Description:功能函數(shù)
4 * Author: bug菌
5/
6void Fuction1(void)
7{
8 ENTER_CRITICAL();//進入臨界區(qū)
9
10 //do something~
11
12 EXIT_CRITICAL();//退出臨界區(qū)
13}
14/*
15 * Function: Fuction2
16 * Description: 功能函數(shù)
17 * Author: bug菌
18 ********************************************/
19void Fuction2(void)
20{
21 ENTER_CRITICAL();//進入臨界區(qū)
22
23 ......
24 Fuction1();
25
26 ......
27 //do something~
28
29 EXIT_CRITICAL();//退出臨界區(qū)
30}
這種臨界區(qū)的使用是很多朋友常犯的錯誤,當然這里的臨界區(qū)操作僅僅只是開關(guān)中斷,許多自己公司寫的,或者裁剪的都是這種簡約開關(guān)中斷版本,所以當調(diào)用Function1函數(shù)以后,后面的代碼就不在臨界區(qū)內(nèi)了,此時就有可能會存在共享問題。
當然目前的開源OS都會提供一種把相關(guān)嵌套標記保存在局部變量中的處理方式,如下代碼所示:
1//來源于ucos源碼
2#define OS_ENTER_CRITICAL() (cpu_sr = OSCPUSaveSR())
3#define OS_EXIT_CRITICAL() (OSCPURestoreSR(cpu_sr))
4
5/*********************************************
6 * Function: Fuction1
7 * Description:功能函數(shù)
8 * Author: bug菌
9 ********************************************/
10void Fuction1(void)
11{
12 int cpu_sr;
13
14 OS_ENTER_CRITICAL();//進入臨界區(qū)
15
16 //do something~
17
18 OS_EXIT_CRITICAL();//退出臨界區(qū)
19}
20
21/*********************************************
22 * Function: Fuction2
23 * Description: 功能函數(shù)
24 * Author: bug菌
25 ********************************************/
26void Fuction2(void)
27{
28 int cpu_sr;
29
30 OS_ENTER_CRITICAL();//進入臨界區(qū)
31
32 Fuction1(void);
33
34 OS_EXIT_CRITICAL();//退出臨界區(qū)
35
36}
為了更好的理解,我寫了一下下面的偽代碼,供大家參數(shù)~
1//中斷寄存器register原本是1, 向register寫0關(guān)中斷,向register寫1開中斷
2
3void Fuction2(void)
4{
5 int cpu_sr1 = 0;
6
7 cpu_sr1 = register;
8 register = 0; //register == 0;cpu_sr1 == 1;
9
10 void Fuction1(void)
11 {
12 int cpu_sr1 = 0;
13
14 cpu_sr2 = register;
15 register = 0; //register == 0;cpu_sr2 == 0;
16
17
18 register = cpu_sr2;
19 cpu_sr2 = 0;//register == 0;cpu_sr2 == 0;
20 }
21
22 register = cpu_sr1;
23 cpu_sr1 = 0;//register == 1;cpu_sr1 == 0;
24
25}
不同的OS可能具體實現(xiàn)有所差異,大體上都一樣~
來源:公眾號,最后一個bug
審核編輯:湯梓紅
-
芯片
+關(guān)注
關(guān)注
455文章
50816瀏覽量
423675 -
cpu
+關(guān)注
關(guān)注
68文章
10863瀏覽量
211782 -
RTOS
+關(guān)注
關(guān)注
22文章
813瀏覽量
119643 -
代碼
+關(guān)注
關(guān)注
30文章
4788瀏覽量
68616
原文標題:RTOS中臨界區(qū)的使用是門技術(shù)活~
文章出處:【微信號:嵌入式情報局,微信公眾號:嵌入式情報局】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論