linux中阻塞和非阻塞的區別
所謂阻塞方式block,顧名思義,就是程序或是執行緒執行到這些函式時必須等待某個事件的發生,如果事件沒有發生,程序或執行緒就被阻塞,函式不能立即返回)。
所謂非阻塞方式non-block,就是程序或執行緒執行此函式時不必非要等待事件的發生,一旦執行肯定返回,以返回值的不同來反映函式的執行情況,如果事件發生則與阻塞方式相同,若事件沒有發生則返回一個程式碼來告知事件未發生,而程序或執行緒繼續執行,所以效率較高。可是使用Select就可以完成非阻塞方式工作的程式,它能夠監視我們需要監視的檔案描述符的變化情況——讀寫或是異常。
----------------------------------------------------------------------------------------------------------------------------------------------------
阻塞:顧名思義,就是指在執行裝置操作時若不能獲得資源則掛起操作,直到滿足可操作的條件後再進行操作,被掛起的程序進入休眠狀態,被從排程器的執行佇列移
走,直到等待的條件滿足。
非阻塞:就是反過來,程序在不能進行裝置操作時並不掛起,它或者放棄,或者不停的查詢,直到可以進行位置。
--------------------------------------------------例子--------------------------------------------------阻塞地讀取串列埠一個字元:
非阻塞地讀取串列埠一個字元:char buf; fd = open("/dev/ttys",O_RDWR); .. .. res = read(fd,&buf,1); //當串列埠上有輸入時才返回 if(res == 1) { printf("%c\n",buf); }
char buf;
fd = open("/dev/ttys",O_RDWR | O_NONBLOCK);
.. ..
while( read(fd,&buf,1) !=1); //當串列埠上無輸入也返回,所
//以要迴圈嘗試讀取串列埠
printf("%c\n",buf);
在Linux裝置驅動中,可以使用等待隊
列(wait queue)來實現阻塞程序的喚醒.等待佇列能夠用於實現核心中的非同步事件通知機制。Linux提供了有關等待佇列的操作:
1) wait_queue_head_t my_queue; //定義等待佇列頭
2) init_waitqueue_head(&my_queue); //初始化佇列頭
如果覺得上邊兩步來的麻煩,可以直接使用DECLARE_WAIT_QUEUE_HEAD(name)
3) DECLARE_WAITQUEUE(name,tsk); //定義等待佇列
4) void fastcall add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
void fastcall remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
用於將等待佇列wait新增到等待佇列頭指向的等待佇列連結串列中 。
5) wait_event(queue, conditon);
wait_event_interruptible(queue, condition);//可以被訊號打斷
wait_event_timeout(queue, condition, timeout);
wait_event_interruptible_timeout(queue, condition, timeout);//不能被訊號打斷
queue:作為等待佇列頭的等待佇列被喚醒
conditon:必須滿足,否則阻塞
timeout和conditon相比,有更高優先順序
6) void wake_up(wait_queue_head_t *queue);
void wake_up_interruptible(wait_queue_head_t *queue);
上述操作會喚醒以queue作為等待佇列頭的所有等待佇列中所有屬於該等待佇列頭的等待佇列對應的程序。
7) sleep_on(wait_queue_head_t *q);
interruptible_sleep_on(wait_queue_head_t *q);
sleep_on作用是把目前程序的狀態置成TASK_UNINTERRUPTIBLE,並定義一個等待佇列,之後把他附屬到等待佇列頭q,直到資源可用,q引導的等待佇列被喚醒。interruptible_sleep_on作用是一樣的, 只不過它把程序狀態置為TASK_INTERRUPTIBLE.
這兩個函式的流程是首先,定義並初始化等待佇列,把程序的狀態置成TASK_UNINTERRUPTIBLE或TASK_INTERRUPTIBLE,並將對待佇列新增到等待佇列頭。
然後通過schedule(放棄CPU,排程其他程序執行。最後,當程序被其他地方喚醒,將等待佇列移除等待佇列頭。
在Linux核心中,使用set_current_state()和__add_wait_queue()函式來實現目前程序狀態的改變,直接使用current->state = TASK_UNINTERRUPTIBLE
類似的語句也是可以的。
因此我們有時也可能在許多驅動中看到,它並不呼叫sleep_on或interruptible_sleep_on(),而是親自進行程序的狀態改變和切換。