一.? 簡介
Linux是一個多任務操作系統,肯定會存在多個任務共同操作同一段內存或者設備的情況, 多個任務甚至中斷都能訪問的資源叫做共享資源,在驅動開發中要注意對共享資源的保護,也就是要處理對共享資源的并發訪問。比如,共享單車,大家按照誰掃誰騎走的原則來共用這個單車,如果沒有這個并發訪問共享單車的原則存在,只怕到時候為了一輛單車要打起來了。
在 Linux 驅動編寫過程中,對于并發控制的管理非常重要。
本文簡單了解一下Linux中并發與競爭的概念。
二.? Linux并發與競爭的基本概念
1.? 并發與競爭簡介
并發就是多個 “用戶” 同時訪問同一個共享資源,比如,你們公司有一臺打印機,你們公司的所有人都可以使用。現在小李和小王要同時使用這一臺打印機,都要打印一份文件。小李要 打印的文件內容如下:
我叫小李
電話:123456
工號:16
小王要打印的內容如下:
我叫小王
電話:678910
工號:20
這兩份文檔肯定是各自打印出來的,不能相互影響。當兩個人同時打印的話如果打印機不做處理的話可能會出現小李的文檔打印了一行,然后開始打印小王的文檔,這樣打印出來的文檔就錯亂 了,可能會出現如下的錯誤文檔內容:
我叫小王
電話:123456
工號:20
可以看出,小王打印出來的文檔中電話號碼錯誤了,變成小李的了,這是絕對不允許的。如果有多人同時向打印機發送了多份文檔,打印機必須保證一次只能打印一份文檔,只有打印完成以后才能打印其他的文檔。
2.? 并發產生的原因
Linux 系統是個多任務操作系統,會存在多個任務同時訪問同一片內存區域,這些任務可 能會相互覆蓋這段內存中的數據,造成內存數據混亂。針對這個問題必須要做處理,嚴重的話 可能會導致系統崩潰。現在的 Linux 系統并發產生的原因很復雜,總結一下有下面幾個主要原 因:
①? 多線程并發訪問, Linux 是多任務 ( 線程 ) 的系統,所以多線程訪問是最基本的原因。
②? 搶占式并發訪問,從 2.6 版本內核開始, Linux 內核支持搶占,也就是說調度程序可以 在任意時刻搶占正在運行的線程,從而運行其他的線程。
③? 中斷程序并發訪問,這個無需多說,學過 STM32 的同學應該知道,硬件中斷的權利可 是很大的。
④ SMP( 多核 ) 核間并發訪問,現在 ARM 架構的多核 SOC 很常見,多核 CPU 存在核間并 發訪問。
并發訪問帶來的問題就是競爭,學過 FreeRTOS 和 UCOS 的同學應該知道臨界區這個概念,所謂的臨界區就是共享數據段,對于臨界區必須保證一次只有一個線程訪問,也就是要保證臨 界區是原子訪問的,這里的原子訪問就表示這一個訪問是一個步驟,不能再進行拆分。 如 果多個線程同時操作臨界區就表示存在競爭。
我們在編寫驅動的時候,一定要注意避免并發和防止競爭訪問。 很多 Linux 驅動初學者往往不注意這一點,在驅動程序中埋下了隱患,這類問題往往又很不容易查找,導致驅動調試難度加大、費時費力。所以,在實現驅動之前就需要考慮到并發與競爭,而不是驅動都編寫完了然后再處理并發與競爭。
3. 保護什么
前面一直說要防止并發訪問共享資源,換句話說就是要保護共享資源,防止進行并發訪問。
在程序中什么是共享資源?也就是保護的內容是什么?
我們保護的不是代碼, 而是數據!某個線程的局部變量不需要保護,我們要保護的是多個線程都會訪問的共享數據。 一個整形的全局變量 a 是數據,一份要打印的文檔也是數據。
雖然我們知道了要對共享數據進行保護,怎么判斷哪些共享數據要保護呢?
找到要保護的數據才是重點,而這個也是難點, 因為驅動程序各不相同,那么數據也千變萬化,一般像全局變量,設備結構體這些肯定是要保 護的,至于其他的數據就要根據實際的驅動程序而定了。
當我們發現驅動程序中存在并發和競爭的時候一定要處理掉。