8.1 阻塞IO、非阻塞IO、等待佇列
阿新 • • 發佈:2018-12-12
阻塞操作是指在執行裝置操作時若不能獲得資源則掛起程序,直到滿足可操作的條件後再進行操作。被掛起的程序進入休眠狀態,被從排程器的執行佇列移走,直到等待的條件被滿足。
非阻塞操作是指程序在不能進行裝置操作時並不掛起,它或者放棄,或者不停地查詢,直至可以進行操作為止。
//阻塞地讀取串列埠一個字元 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 }