在RTOS中,是否可以使用全局變數來實現同步,存在哪些風險?
01-26
RTOS中常使用隊列與信號量來實現同步,那麼是否可以使用全局變數實現同步,存在哪些風險?
不能用全局變數。
分單核和多核來討論。
單核的情況下
C代碼if (global == 1) ...
對應x86彙編:
mov eax, [_global_addr]
cmp eax, 1
jz xxxx
如果在mov指令之後發生一次任務切換,在其它任務中global的值被修改,則這段代碼中使用的仍然是global的舊值,執行結果將不符合預期。其他arch也有類似的問題。
多核情況下
global的值可能在不同的核的L1 cache里,這種情況下cache的一致性不一定正確。
具體原因比較複雜,不展開說。
鎖的作用:
1. 保證鎖範圍內的操作不發生任務切換;
2. 保證cache一致性;
鎖實際上是在保證這兩條的基礎上,再用類似全局變數的機制實現的,自己只用一個全局變數,不用額外的保護是不行的。
--------------------------------------
評論區中有人提到在某些環境下這麼用沒問題,這是由於任務調度模型設置的問題,比如沒有輪詢式調度,或者搶佔的時間點不夠好,或者任務模型太簡單,或者CPU太快,但不代表在任何場景下沒問題,安全的做法還是要在多線程的環境下使用操作系統提供的鎖來保證數據的一致性。這個問題就不該問,你把演算法寫出來,然後問你自己哪個操作是原子操作這個問題就有答案了。
其實在某些較為簡單的使用場景下,也並非不能使用全局變數來實現同步,例如在某線程中循環等待一個全局變數等於1,另外一個單一線程中對該全局變數進行賦值操作。但僅限於很簡單的類似的場景下,較為複雜的還是應該使用消息隊列等機制。一般用到RTOS的應用場景都不會特別複雜,更多的我們只是需要OS的一個調度功能,甚至是非搶佔式的,所以也並不是絕對不能使用全局變數來作同步,起碼我本人就少量的使用過。
你用全局變數,還得以輪訓的方式去check 全局變數的變化,這是存在cpu開銷的.不懂RTOS,但general-purpose operating systems 而言,很多實現上系統調用會觸發content switch,進行線程,進程切換。
你如果是使用全局變數,那就無法利用這種content switch的機制了,cpu調度上會沒那麼高效。
推薦閱讀: