天天看點

linux阻塞和休眠,Linux裝置驅動之阻塞與非阻塞IO

阻塞是指在執行裝置操作時若不能獲得資源則挂起程序,直到滿足可操作的條件後再進行操作。被挂起的程序将進入休眠狀态,被從排程器的運作隊列移走,直到條件被滿足。而非阻塞操作的程序在不能進行裝置操作時并不挂起,它或者放棄,或者不停的查詢(一直占用CPU),直到可以進行操作為止。

Linux驅動程式中使用等待隊列(wait_queue)來實作阻塞程序的喚醒。

靜态方法定義并初始化一個等待隊列頭:

DECLARE_WAIT_QUEUE_HEAD(name);

或者使用動态方法:

wait_queue_head mane;

init_watiqueue_head(&name);

等待事件:

conditions為任意一個布爾值,若為真,程序被喚醒,否則休眠。後兩個版本隻會等待給定的時間,到期時,這兩個宏都會傳回0值,而無論conditions如何求值。

wait_event(queue, conditions);程序将被置于非中斷休眠,這通常不是我們所期望的

wait_event_interruptible(queue, conditions);最好選擇此方式,它可以被信号中斷。傳回非0表示被某個信号中斷。

wait_event_timeout(queue, conditions,timeout);

wait_event_interruptible_timeout(queue, conditions,timeout);

喚醒:

阻塞的另外一半是喚醒。其它的某個執行線程(可能是另一個程序或者為斷處理例程)必須為我們執行喚醒,因為我們的程序正在休眠中。用來喚醒休眠程序的基本函數是wake_up,它有多種形式:

void wake_up(wait_queue_head_t *queue);

void wake_up_interruptible(wait_queue_head_t *queue);隻會喚醒那些執行中可中斷休眠的程序。

在實踐中,約定作法是wait_event時使用wake_up,使用wait_event_interruptible時使用 wake_up_interruptible。

示例代碼:任何試圖從該裝置讀取的程序均被置于休眠,隻要某個程序向該裝置寫入,所有的休眠的程序将被喚醒。

static DECLARE_WAIT_QUEUE_HEAD(wq);

static int flag=0;

ssize_t sleepy_read(struct file *filp,char __user *buf,size_t count,loff_t *pos)

{

wait_event_interruptible(wq,flag!=0);

flag = 0;

.....

.....

return 0;

}

ssize_t sleepy_write(struct file *filp,char __user *buf,size_t count,loff_t *pos)

{

flag = 1 ;

wake_up_interruptible(&wq);

return count;

}