併發與競態及解決途徑
併發(concurrency)是指多個執行單元同時、並行的被執行,而併發執行單元對共享資源的訪問很容導致競態(race condition)。
併發與競態發生的條件:對稱多處理器(smp)的多個cpu;單cpu內程序與搶占它的程序;中斷與程序之間。
解決併發與競態的途徑
訪問共享資源的**區域稱為臨界區域(critical section),解決競態的根本途徑就是對臨界區的互斥訪問,方法主要有中斷遮蔽、原子操作、自旋鎖、訊號量、互斥體。
1、中斷遮蔽
單cpu避免競態的簡單辦法就是中斷遮蔽,保證可以防止中斷與程序間競態條件的發生(所有中斷被遮蔽後程序間切換的基礎時鐘中斷也被遮蔽掉了)。
使用方法:
local_irq_disable()//禁止本地cpu的中斷
......
critical section
......
local_irq_enable()
中斷對保證系統正常執行非常重要,長時間遮蔽中斷會讓系統很危險。
2、原子操作
原子操作是指在執行過程中不會被別的**路徑所中斷,可分為整形原子操作和位原子操作。
整形原子操作
atomic_t v;//定義原子變數v
void atomic_set(atomic_t *v, int i); //設定原子變數v的值為i
atomic_t v=atomic_int(0); //定義原子變數v,並初始化為0
atomic_read(atomic_t *v); //獲取原子變數的值
void atomic_add(int i, atomic_t *v); //原子變數加i
void atomic_sub(int i, atomic_t *v); //原子變數減i
位原子操作
void set_bit(nr, void *addr); //設定addr指向的值的nr位為1
void clear_bit(nr, void *addr);
void change_bit(nr, void *addr); //第nr位取反
test_bit(nr, void *addr); //測試位
3、自旋鎖
自旋鎖主要針對smp或單cpu且核心可搶占的情況,自旋鎖可以保證臨界區不受別的cpu和本cpu內的搶占程序打擾。當臨界區可能受到中斷和底半步影響時,應該使用自旋鎖的衍生操作。
自旋鎖是忙等待鎖,當鎖不可用時,cpu會不停地迴圈測試而不能做其它的工作,因此自旋鎖會降低系統的效能。
如果臨界區域發生阻塞,可能會導致死鎖,因此在自旋鎖占有期間內不能呼叫copy_from_user(), copy_to_user(), kmalloc()等函式
spinlock_t lock; //定義自旋鎖
spin_lock_init(&lock); //初始化自旋鎖
spin_lock(&lock); //獲得自旋鎖
spin_trylock(&lock); //嘗試獲得自旋鎖
spin_unlock(&lock); //釋放自旋鎖
4、訊號量
訊號量和自旋鎖不同的地方在於當程序得不到訊號量時,程序會進入休眠或其它狀態。
struct semaphore sem; //定義訊號量
void sema_init(struct semaphore *sem, int val); //初始化訊號量sem, 並把它的值設為val
declare_mutex(name) //定義並初始化,相當於上面兩句
declare_mutex_locked(name) //定義並初始化
void down(struct semaphore *sem); // 獲得訊號量,不能在中斷上下文中使用,進入睡眠後不能用訊號打斷
int down_interruptible(struct semaphore *sem); //進入睡眠後可被訊號打斷
int down_trylock(struct semaphore *sem); //嘗試獲得訊號量,不會睡眠,可以在中斷上下文中使用
void up(struct semaphore *sem); //釋放訊號量
5、互斥體
互斥體完成的功能與訊號量非常相識。
struct mutex my_mutex; //定義互斥體
mutex_init(&my_mutex); //初始化互斥體
void fastcall mutex_lock(struct mutex *lock); //獲取互斥體
int fastcall mut當ex_lock_interruptiable(struct mutex *lock);
int fastcall mytex_trylock(struct mutex *lock);
void fastcall mutex_unlock(struct mutex *lock); //釋放互斥體
自旋鎖vs訊號量
當臨界區執行時間比較小時,採用自旋鎖,否則採用訊號量;
自旋鎖絕對不能在臨界區包含可能引起阻塞的**,訊號量可以;
如果臨界區的**在中斷中執行,應該使用自旋鎖或訊號量的down_trylock()函式。
併發與競態
linux是乙個多工的作業系統,在多個程序同時執行時,就有可能為了競爭同乙個資源發生堵塞。以下是解決的幾種方法 1 訊號量 declare mutex sem if down interruptible sem critical section up sem 2 完成量 declare comple...
併發競態的解決方法
有多個程序同時訪問同乙個驅動程式中的臨界資源的時候,競態就會產生了。競態產生的根本原因 1.對於單核cpu,核心支援搶占。2.多核cpu,核與核之間會產生競態 3.中斷和程序間也會產生競態 4.中斷和中斷間產生競態 中斷巢狀可以 arm架構不支援 一 中斷遮蔽 了解 中斷遮蔽只適合在單核cpu。中斷...
LDD 併發和競態
1.正在執行的多個使用者空間程序可能以一種令人驚訝的組合方式訪問我們的 2.smp系統甚至可在不同的處理器上同時執行我們的 3.核心是可搶占的,驅動程式 可能在任何時候丟失對處理器的獨佔 4.裝置中斷時非同步事件,可能導致 的併發執行 5.核心還提供了許多可延遲 執行的機制,比如workqueue ...