臨界區問題是嵌入式軟體編程一個不得不面對的關鍵性問題。特別對於底層驅動,代碼在記憶體中只有一份,上層的多任務或者多進程,都會對同一個驅動去訪問,這樣不可避免的遇到了任務之間打架的問題,處理好這個問題是區分一個菜鳥和老鳥的根本性關鍵之一。
接下來談談臨界區產生的原因:
假設有以下代碼:
[cpp]
view plaincopyprint?
- int x;
-
- void process_data()
- {
- x++;
-
- }
int x; void process_data(){ x++; }
假如在一個可以搶佔的作業系統上有兩個任務task1, task2, 全域變數x 的初始值為0, 現在兩個任務task1, task2 同時去訪問process_data 這個函數,兩個任務各執行一次process_data 這個函數,等到兩個人執行完畢後,試問x的值是多少?大部分人可能會回答為2。沒有作業系統的時候,的卻不錯,調用函數2次,就是2.問題是有了作業系統就沒這麼簡單了,一個任務執行期間,隨時可能會被另外一個任務給打斷,這樣就會造成臨界區的問題。
首先明確一個基本概念,在作業系統中每一個任務都有自己的一套寄存器,各個任務間的寄存器值很可能是不一樣的。
下面來具體分析這個問題產生的根本原因:
x++ 不是一個原子型的操作,它的彙編函數有3句,分別是:
1 ldr r1, [mem]
2 add r1, r1, #1
3 strr1 [mem]
假如任務task1 剛執行完2即 add r1, r1,#1,因為是可以搶佔的作業系統,所以被任務task 2 給搶佔了,然後task 2 執行完1,2,3 這三個步驟後還給任務task 1.
如前所述,圖中的task1 和task2 的寄存器值是不同的,因為任務各自有自己的一套寄存器。讀者可以推導一下,x 的最終值是1而不是2!
所以在多任務的情況下,共同去訪問一個全域變數,會產生臨界區的問題,如之前所述最終值可能是不確定的,可能是1也可能是2,所以需要採用作業系統的一定機制去保護它。