為什么會產(chǎn)生并發(fā)
1、多個用戶同時登陸的時候,他們有可能在任何時刻以任意的組合調(diào)用內(nèi)核代碼。
2、smp系統(tǒng)可能同時在不同的處理器上執(zhí)行你的代碼。
3、內(nèi)核代碼是搶占式的,你的程序有可能隨時被剝奪掉處理器。
4、設(shè)備中斷可能導(dǎo)致并發(fā)的異步事件。
5、內(nèi)核也提供了各種延遲代碼執(zhí)行機(jī)制,如工作隊列等,任務(wù)隊列和定時器,它可以使你在與當(dāng)前進(jìn)程無關(guān)的方法中運行代碼
并發(fā)帶來的影響
并發(fā)產(chǎn)生了競爭條件,比如兩個進(jìn)程同時訪問相同的硬件資源
應(yīng)對的基本原則是:盡量避免共享數(shù)據(jù)
如果無法避免那就一定要注意共享的數(shù)據(jù)。
Linux 的 信號量
#include <linux/semaphore.h>
/*
* Copyright (c) 2008 Intel Corporation
* Author: Matthew Wilcox <willy@linux.intel.com>
*
* Distributed under the terms of the GNU GPL, version 2
*
* Please see kernel/semaphore.c for documentation of these
functions
*/
#ifndef __LINUX_SEMAPHORE_H
#define __LINUX_SEMAPHORE_H
#include <linux/list.h>
#include <linux/spinlock.h>
/* Please don't access any members of this structure directly */
struct semaphore {
raw_spinlock_t lock;
unsigned int count;
struct list_head wait_list;
};
#define __SEMAPHORE_INITIALIZER(name , n)
{
.lock = __RAW_SPIN_LOCK_UNLOCKED((name).lock),
.count = n,
.wait_list = LIST_HEAD_INIT((name).wait_list),
} #
define DEFINE_SEMAPHORE(name) struct semaphore name = __SEMAPHORE_INITIALIZER(name , 1)
static inline void sema_init(struct semaphore *sem, int val)
{
static struct lock_class_key __key;
*sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val);
lockdep_init_map(&sem->lock.dep_map , "semaphore ->lock", &__key , 0);
}
extern void down(struct semaphore *sem);
extern int __must_check down_interruptible(struct semaphore *sem);
extern int __must_check down_killable(struct semaphore *sem);
extern int __must_check down_trylock(struct semaphore *sem);
extern int __must_check down_timeout(struct semaphore *sem, long jiffies);
extern void up(struct semaphore *sem);
#endif /* __LINUX_SEMAPHORE_H */
down方法將信號量的值減一然后等到信號量的值大于等于零繼續(xù)執(zhí)行。
down_interruptible跟down類似但是可以被中斷,建議使用這個API,只使用down容易造成該線程永遠(yuǎn)無法退出。
一般的使用方法是:
if (down_interruptible(&sem))
return -ERESTARTSYS;
讀寫信號量
一種常見的信號量,針對共享文件,允許多個線程同時讀,而讀的時候不允許寫。在同一時間只允許一個線程寫。
#include <linux/rwsem.h>
自旋鎖
自旋鎖最初是為了SMP系統(tǒng)設(shè)計的,實現(xiàn)在多處理器情況下保護(hù)臨界區(qū)。
自旋鎖只有兩種狀態(tài),上鎖,未上鎖,經(jīng)常被用來確保一段代碼的原子性
spinlock API:
void spin_lock(spinlock_t *lock);
void spin_lock_irqsave(spinlock_t *lock , unsigned long flags);
void spin_lock_irq(spinlock_t *lock);
void spin_lock_bh(spinlock_t *lock);
讀寫自旋鎖
linux內(nèi)核提供了讀寫自旋鎖,實際上它與讀寫信號量很相似。
上鎖的要求
1、如果你在自己的代碼里實現(xiàn)了一個設(shè)備鎖,而你也要套用到linux內(nèi)核提供的鎖,請先把自己的鎖鎖上,再把系統(tǒng)的鎖鎖上。
2、如果你使用信號量和自旋鎖,請先down信號量,再使用自旋鎖。
3、確保自旋鎖內(nèi)沒有其他的鎖,以防系統(tǒng)被死鎖。