1. 程式人生 > >8.1 阻塞IO、非阻塞IO、等待佇列

8.1 阻塞IO、非阻塞IO、等待佇列

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

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

//阻塞地讀取串列埠一個字元
char buf;
fd = open("/dev/ttyS1", O_RDWR);
...
res = read(fd,&buf,1); //當串列埠上有輸入時才返回
if(res==1)
printf("%c\n", buf);



//非阻塞地讀取串列埠一個字元
char buf;
fd = open("/dev/ttyS1", O_RDWR| O_NONBLOCK);
...
while(read(fd,&buf,1)!=1); //串列埠上無輸入也返回,所以要迴圈嘗試讀取串列埠
printf("%c\n", buf);

等待佇列

作用:實現阻塞程序的喚醒

wait_queue_head_t my_queue;   //定義“等待佇列頭”。
init_waitqueue_head(&my_queue);//初始化“等待佇列頭”。
DECLARE_WAIT_QUEUE_HEAD (name)//定義並初始化“等待佇列頭”。


DECLARE_WAITQUEUE(name, tsk)//定義並初始化等待佇列


void fastcall add_wait_queue(wait_queue_head_t *q, wait_queue_t*wait);
//新增等待佇列wait到q指向的等待佇列連結串列
void fastcall remove_wait_queue(wait_queue_head_t *q, wait_queue_t*wait);
//從q指向的等待佇列連結串列中移除等待佇列wait


//等待事件
//引數queue等待佇列被喚醒,引數condition 必須滿足,否則阻塞
wait_event(queue, condition) //不可以被訊號打斷
wait_event_interruptible(queue, condition)//可以被訊號打斷
wait_event_timeout(queue, condition, timeout)//阻塞等待時間到達,不論是否滿足條件都返回
wait_event_interruptible_timeout(queue, condition, timeout)//同上,但可被訊號打斷


//喚醒佇列
//所有屬於queue等待佇列對應的程序。
void wake_up(wait_queue_head_t *queue);//喚醒處於深睡眠和淺睡眠程序
void wake_up_interruptible(wait_queue_head_t *queue);//喚醒淺睡眠程序


//在等待佇列上睡眠
sleep_on(wait_queue_head_t *q );//將程序的狀態置為深睡眠TASK_UNINTERRUPTIBLE
interruptible_sleep_on(wait_queue_head_t *q );//將程序的狀態置為淺睡眠TASK_INTERRUPTIBLE


//實際應用中,並不呼叫sleep_on()或interruptible_sleep_on(),而是親自進行程序的狀態改變和切換
1 static ssize_t xxx_write(struct file *file, const char *buffer,size_t count,
2                         loff_t *ppos)
3 {
4 ...
5 DECLARE_WAITQUEUE(wait, current); //定義等待佇列
6 _ _add_wait_queue(&xxx_wait, &wait); //新增等待佇列
7
8 ret = count;
9 /* 等待裝置緩衝區可寫*/
10 do
11 {
12 avail = device_writable(...);
13 if (avail < 0)
14 _ _set_current_state(TASK_INTERRUPTIBLE);//改變程序狀態
15
16 if (avail < 0)
17 {
18 if (file->f_flags &O_NONBLOCK) //非阻塞
19 {
20 if (!ret)
21 ret = - EAGAIN;
22 goto out;
23 }
24 schedule(); //排程其他程序執行,放棄CPU
25 if (signal_pending(current))//如果是因為訊號喚醒
26 {
27 if (!ret)
28 ret = - ERESTARTSYS;
29 goto out;
30 }
31 }
32 }while (avail < 0);
33
34 /* 寫裝置緩衝區*/
35 device_write(...)
36 out:
37 remove_wait_queue(&xxx_wait, &wait);//將等待佇列移出等待佇列頭
38 set_current_state(TASK_RUNNING);//設定程序狀態為TASK_RUNNING
39 return ret;
40 }