1. 程式人生 > >字元裝置中的同步、互斥和阻塞操作

字元裝置中的同步、互斥和阻塞操作

下面的內容對學習過程中做一個簡單的總結,方便以後回憶,內容可能過於簡陋

1. 原子操作

如果我們希望字元驅動程式每次只能給一個應用程式開啟,就需要加鎖,比如在驅動程式中加一個整型的全域性變數canopen:     1代表可以open,0代表不能open。 但是我們不能簡單的給整型變數canopen++或者canopen--,因為程式碼中簡單的自加動作,在彙編程式碼中就要分成3步完成:     ldr ... 讀出     add ... 加操作     str ...  回寫值

假如A、B兩個程式同時操作變數canopen = 1,在多工的情況下就會有問題,比如:

                    A                                                                                                    B         讀出canopen,此時值為1         被切換出執行佇列                                                                   讀出canopen,此時值為1                                                                                                         canopen--,此時值為0                                                                                                         open字元裝置成功         此時A程式重新開始執行,進行canopen--,值為0         open字元裝置也成功

由上面的分析可知,簡單的加減是不可靠的,可以使用原子操作:

原子操作指的是在執行過程中不會被別的程式碼路徑所中斷的操作。 常用原子操作函式舉例:

atomic_t v = ATOMIC_INIT(0);     //定義原子變數v並初始化為0
atomic_read(atomic_t *v);        //返回原子變數的值
void atomic_inc(atomic_t *v);    //原子變數增加1
void atomic_dec(atomic_t *v);    //原子變數減少1
int atomic_dec_and_test(atomic_t *v); //自減操作後測試其是否為0,為0則返回true,否則返回false。

2. 訊號量

訊號量(semaphore)是用於保護臨界區的一種常用方法,只有得到訊號量的程序才能執行臨界區程式碼。 當獲取不到訊號量時,程序進入休眠等待狀態。

定義訊號量
struct semaphore sem;
初始化訊號量
void sema_init (struct semaphore *sem, int val);
void init_MUTEX(struct semaphore *sem);//初始化為0

也可以用下面的巨集定義:
static DECLARE_MUTEX(button_lock);     //定義互斥鎖

open時獲得訊號量:
void down(struct semaphore * sem); //down(&button_lock) //非第一個獲取訊號量的程式都要進入休眠狀態,直到第一個獲取訊號量的程式釋放鎖
int down_interruptible(struct semaphore * sem); //加了interruptible,說明就算休眠了也能被別人打斷
int down_trylock(struct semaphore * sem);  //down_trylock(&button_lock)

close時釋放訊號量:
void up(struct semaphore * sem); //up(&button_lock);

3. 阻塞

阻塞操作     是指在執行裝置操作時若不能獲得資源則掛起程序,直到滿足可操作的條件後再進行操作。 被掛起的程序進入休眠狀態,被從排程器的執行佇列移走,直到等待的條件被滿足。

非阻塞操作   程序在不能進行裝置操作時並不掛起,它或者放棄,或者不停地查詢,直至可以進行操作為止。

fd = open("...", O_RDWR | O_NONBLOCK); //傳入O_NONBLOCK標誌位給底層驅動程式

在驅動程式中就可以這麼使用:

if (file->f_flags & O_NONBLOCK)
{
	if (沒有檢測事件的發生)
		return -EBUSY;
}
else
{
	//進入休眠的狀態
	wait_event_interruptible(...);
}