1. 程式人生 > >阻塞與非阻塞I/O

阻塞與非阻塞I/O

一,阻塞與非阻塞

阻塞是指沒有獲得資源則掛起程序,直到獲得資源為止。被掛起的程序進入休眠狀態,被排程器的執行佇列移走,直到等待條件被滿足。
非阻塞是不能進行裝置操作時不掛起,或放棄,或反覆查詢,直到可以進行操作為止。

驅動程式常需要這種能力:當應用程式進行read(),write()等系統呼叫時,若裝置的資源不能獲取,而使用者又希望以阻塞的方式訪問裝置,驅動程式應該在裝置驅動程式的xxx_read(),xxx_write()等操作中將程序阻直到資源可以獲取,以後,應用程式的read(),write()等呼叫返回,整個過程仍然進行了正確的裝置訪問,使用者並沒有感知到;若使用者以非阻塞的方式訪問裝置檔案,則當裝置資源不可獲取時,裝置驅動的xxx_read(),xxx_write()等操作應立即返回,read(),write()等系統呼叫也隨即被訪問。
阻塞不是低效率,如果裝置驅動不阻塞, 使用者想獲取裝置資源只能不斷查詢,消耗CPU資源,阻塞訪問時,不能獲取資源的程序將進入休眠,將CPU資源讓給其他資源。
阻塞的程序會進入休眠狀態,因此,必須確保有一個地方能喚醒休眠的程序。喚醒程序的地方最大可能發生在中斷裡面,因為硬體資源獲得的同時往往伴隨著一箇中斷

eg1:阻塞地讀取串列埠一個字元
  1. char buf;  
  2. fd=open("/dev/ttyS1",O_RDWR);  
  3. ...  
  4. res=read(fd,&buf,1);//當串列埠有輸入時才返回  
  5. if(res==1)  
  6.     printf("%c\n",buf);  
eg2:非阻塞地讀取串列埠一個字元
  1. char buf;  
  2. fd=open("/dev/ttyS1",O_RDWR|O_NONBLOCK);  //O_NONBLOCK設定為非阻塞方式
  3. ...  
  4. while(read(fd,&buf,1)!=1);//串列埠上無輸入也返回,所以要迴圈嘗試讀取串列埠  
  5. printf("%c\n",buf); 
     
二,等待佇列
在linux驅動程式中,可使用等待佇列(wait queue)來實現阻塞程序的喚醒,以佇列為基礎資料結構,與程序排程機制緊密結合,用於實現核心中的非同步事件通知機制,也可用於同步對系統資源的訪問。
定義"等待佇列頭"
  1. wait_queue_head_t my_queue;  
初始化"等待佇列頭"
  1. init_waitqueue_head(&my_queue);  
巨集名用於定義並初始化,相當於"快捷方式"
  1. DECLARE_WAIT_QUEUE_HEAD (name);  
定義等待佇列
  1. DECLARE_WAITQUEUE(name,tsk);定義並初始化一個名為name的等待佇列  
新增/移除等待佇列
  1. void fastcall add_wait_queue(wait_queue_head_t *q,wait_queue_t *wait);  
  2. void fastcall remove_wait_queue(wait_queue_head_t *q,wait_queue_t *wait);  

等待事件 :即程序的等待條件

休眠佇列

  1. wait_event(queue,condition);等待以queue為等待佇列頭等待佇列被喚醒,condition必須滿足,否則阻塞  
  2. wait_event_interruptible(queue,condition);可被訊號打斷  
  3. wait_event_timeout(queue,condition,timeout);阻塞等待的超時時間,時間到了,不論condition是否滿足,都要返回  
  4. wait_event_interruptible_timeout(queue,condition,timeout)  
喚醒佇列
  1. void wake_up(wait_queue_head_t *queue);  
  2. void wake_up_interruptible(wait_queue_head_t *queue);  
上述操作喚醒以queue作為等待佇列頭的所有等待佇列中所有屬於該等待佇列頭的等待佇列對應的程序。
wake_up()與wake_event()或者wait_event_timeout成對使用,
wake_up_intteruptible()與wait_event_intteruptible()或者wait_event_intteruptible_timeout()成對使用。

三,輪詢操作

在使用者程式中,select()和poll()也是與裝置阻塞與非阻塞訪問的,使用非阻塞I/O的應用程式常會使用select()和poll()系統呼叫查詢是否可對裝置進行無阻塞的訪問。
select()和poll()系統呼叫最終會引發裝置驅動中的poll()函式被執行。
應用程式中的輪詢程式設計
  1. int select(int numfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,  
  2.     struct timeval *timeout);  

功能:測試指定的fd可讀?可寫?有異常條件待處理?

readfds,writefds,exceptfds是被select監視的讀,寫,異常處理的檔案描述符集合。

numfds是需要檢查的號碼最高的檔案描述符加1,timeout引數是一個指向struct timeval型別的指標,它可以使select()在等待timeout時間後若沒有檔案描述符準備好則返回。timeout為NULL,select將阻塞程序,直至某個檔案滿足要求。
  1. struct timeval  
  2. {  
  3.     int tv_sec;  
  4.     int tv_usec;  
  5. };  
  1. FD_ZERO(fd_set *set);//清除一個檔案描述符  
  2. FD_SET(int fd,fd_set *set);//將一個檔案描述符加入檔案描述符集中  
  3. FD_CLR(int fd,fd_set *set);//將一個檔案描述符從檔案描述符集中清除  
  4. FD_ISSET(int fd,fd_set *set);//判斷檔案描述符是否被置位  
裝置驅動中的輪詢程式設計
裝置驅動中poll()函式:
  1. unsigned int (*poll)(struct file *filp, struct poll_table *wait);  
主要進行兩項工作:
1.對可能引起裝置檔案狀態變化的等待佇列呼叫poll_wait()函式,將對應的等待佇列頭新增到poll_table;
2.返回表示是否能對裝置進行無阻塞讀,寫訪問的位掩碼。

用於向poll_table註冊等待佇列的poll_wait()函式的原型

  1. void poll_wait(struct file *filp,wait_queue_head_t *queue,poll_table *wait);  
此函式用於將當前程序新增到wait引數指定的等待列表(poll_table)中。
驅動程式poll()返回裝置資源的可獲取狀態,POLLIN(定義為0x0001) | POLLRDNORM 意味著裝置可以無阻塞地讀,POLLOUT(定義為0x0004) | POLLWRNORM 意味著可以無阻塞的寫。
eg3:poll()函式典型模板
  1. static unsigned int xxx_poll(struct file *filp,poll_table *wait)  
  2. {  
  3.     unsigned int mask=0;  
  4.     struct xxx_dev *dev=filp->private_data;  
  5.     ...  
  6.     poll_wait(filp,&dev->r_wait,wait);  
  7.     poll_wait(filp,&dev->w_wait,wait);  
  8.     if(read_buffer_not _empty)//可讀  
  9.     {  
  10.         mask|= POLLIN |POLLRDNORM;//資料可獲得  
  11.     }  
  12.     if(write_buffer_not _full)//可寫  
  13.     {  
  14.         mask|= POLLOUT|POLLWRNORM;//資料可寫入  
  15.     }  
  16.     ...  
  17.     return mask;  
  18. }  
  1. eg4:globalfifo裝置驅動的poll()函式  
  1. static unsigned int globalfifo_poll(struct file *filp,poll_table *wait)  
  2. {  
  3.     unsigned int mask=0;  
  4.     struct globalfifo_dev *dev=filp->private_data;  
  5.     down(&dev->sem);  
  6.     poll_wait(filp,&dev->r_wait,wait);  
  7.     poll_wait(filp,&dev->w_wait,wait);  
  8.     //fifo非空  
  9.     if(dev->current_len!=0)  
  10.     {  
  11.         mask|=POLLIN |POLLRDNORM;//標示資料可獲得    
  12.     }  
  13.     //fifo非滿  
  14.     if(dev->current_len!=GLOBALFIFO_SIZE)  
  15.     {  
  16.         mask|=POLLOUT |POLLWRNORM;  
  17.     }  
  18.     up(&dev->sem);  
  19.     return mask;  
  20. }<

在測試程式中select()

main()
{
  int fd, num;
  char Buf[128]="memdev_poll test!";
  fd_set rfds,wfds;
 
  /*以非阻塞方式開啟/dev/memdev0裝置檔案*/
  fd = open("/dev/memdev0", O_RDWR | O_NONBLOCK);
  if (fd !=  - 1)
  {
    while (1)
        {
              FD_ZERO(&rfds);
              FD_ZERO(&wfds);
              FD_SET(fd, &rfds);
              FD_SET(fd, &wfds);

              select(fd + 1, &rfds, &wfds, NULL, NULL);
              /*資料可獲得*/
              if (FD_ISSET(fd, &rfds))
              {
                  printf("Poll monitor:can be read\n");
            lseek(fd, 0, SEEK_SET);
            read(fd, Buf, sizeof(Buf));
            printf("Read Buf: %s\n", Buf);
            sleep(1);
              }
              /*資料可寫入*/
              if (FD_ISSET(fd, &wfds))
              {
                  printf("Poll monitor:can be written\n");
            lseek(fd, 0, SEEK_SET);
            write(fd, Buf, sizeof(Buf));
            printf("Write Buf: %s\n", Buf);
            sleep(1);
              }      
       }
  }
  else
  {
    printf("Device open failure\n");
  }
}


相關推薦

socket阻塞阻塞 同步非同步 I/O模型

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

socket阻塞阻塞,同步非同步、I/O模型(轉載只為查閱方便,若有侵權,立刪)

socket阻塞與非阻塞,同步與非同步 作者:huangguisu     1. 概念理解        在進行網路程式設計時,我們常常見到同步(Sync)/非同步(Async),阻塞(Block)/非阻塞(Unbl

聊聊阻塞阻塞、同步非同步、I/O模型

1. 概念理解 在進行網路程式設計時,我們常常見到同步(Sync)/非同步(Async),阻塞(Block)/非阻塞(Unblock)四種呼叫方式: 同步/非同步主要針對C端:  同步: 所謂同步,就是在c端發出一個功能呼叫時,在沒有得到結果之前,該呼叫就不返回。也就是必須一件一件事做,等前一件做完了才能做

網路程式設計中阻塞阻塞、同步非同步、I/O模型的理解

1. 概念理解      在進行網路程式設計時,我們常常見到同步(Sync)/非同步(Async),阻塞(Block)/非阻塞(Unblock)四種呼叫方式:同步:所謂同步,就是在發出一個功能呼叫時,在沒有得到結果之前,該呼叫就不返回。也就是必須一件一件事做,等前一件做完了才能做下一件事。 例如

socket阻塞阻塞,同步非同步、I/O模型

1. 概念理解      在進行網路程式設計時,我們常常見到同步(Sync)/非同步(Async),阻塞(Block)/非阻塞(Unblock)四種呼叫方式: 同步/非同步主要針對C端: 同步:所謂同步,就是在c端發出一個功能呼叫時,在沒有得到結果之前,該

阻塞阻塞I/O

一,阻塞與非阻塞 阻塞是指沒有獲得資源則掛起程序,直到獲得資源為止。被掛起的程序進入休眠狀態,被排程器的執行佇列移走,直到等待條件被滿足。非阻塞是不能進行裝置操作時不掛起,或放棄,或反覆查詢,直到可以進行操作為止。驅動程式常需要這種能力:當應用程式進行read(),wri

Linux裝置驅動中的阻塞阻塞I/O

阻塞和非阻塞I/O是裝置訪問的兩種不同模式,驅動程式可以靈活的支援使用者空間對裝置的這兩種訪問方式 本例子講述了這兩者的區別 並實現I/O的等待佇列機制, 並進行了使用者空間的驗證 基本概念: 1> 阻塞操作      是指 在執行裝置操作時,若不能獲得資源,則掛起程

linux裝置驅動之阻塞阻塞I/O

先做一下與核心阻塞有關的知識儲備: 1)程序休眠:     程序休眠,簡單的說就是正在執行的程序讓出CPU。休眠的程序會被核心擱置在在一邊,只有當核心再次把休眠的程序喚醒,程序才會會重新在CPU執行。這是核心中的程序排程。一個CPU在同一時間只能有一個程序在執行,微觀序列巨

同步非同步I/O阻塞阻塞

        這段時間自己一直在糾結同步和非同步I/O的概念,網上的說法不一,令我感到十分的疑惑,後面是看了Unix網路程式設計,才對這對概念有了比較清晰的認識,所以我只是書本的搬運工。         總的一句話就是“只要I/O過程中引起了程序阻塞就是同步I/O,反之則

Linux 裝置驅動中的阻塞阻塞I/O

何謂阻塞與非阻塞I/O?簡單來說就是對I/O操作的兩種不同的方式。 阻塞:當操作I/O裝置時,如果不能得到相應的資源,則該程序進入休眠狀態,被從排程器的佇列中移走,直到等待的條件滿足。 阻塞的讀取一個字元: char buf; fd = open("/dev/ttyS

Socket編程中,阻塞阻塞的區別

軟件 復用 優點 調用 服務器 運用 需要 默認 con   阻塞:一般的I/O操作可以在新建的流中運用.在服務器回應前它等待客戶端發送一個空白的行.當會話結束時,服務器關閉流和客戶端socket.如果在隊列中沒有請示將會出現什麽情況呢?那個方法將會等待一個的到來.這個行為

同步異步、阻塞阻塞

阻塞與非阻塞 就會 結束 檢查 通信機制 得到 node 分布 好書 “阻塞”與"非阻塞"與"同步"與“異步"不能簡單的從字面理解,提供一個從分布式系統角度的回答。1.同步與異步同步和異步關註的是消息通信機制 (synchronous communication/ a

阻塞阻塞,同步異步

通過 部件 一個 socket 沒有 事件觸發 sel syn 就會 在進行網絡編程時,我們常常見到同步(Sync)/異步(Async),阻塞(Block)/非阻塞(Unblock)四種調用方式:同步: 所謂同步,就是在發出一個功能調用時,在沒有得到結果之前,

同步異步,阻塞阻塞

消息 阻塞 結果 阻塞與非阻塞 過程調用 函數 異步 非阻塞 完成 異步的概念和同步相對。當一個同步調用發出後,調用者要一直等待返回消息(結果)通知後,才能進行後續的執行;當一個異步過程調用發出後,調用者不能立刻得到返回消息(結果)。實際處理這個調用的部件在完成後,通過狀態

關於veriolg中阻塞阻塞賦值問題

觸發 改變 希望 到來 決定 工作 執行 為什麽 個人 在一開始學到阻塞和非阻塞的時候,所被告知的兩者的區別就在於阻塞是串行的,非阻塞是並行的。但是雖然知道這個不同點,有些時候還是很難真正區分用兩者電路的區別,在這就通過幾個例子來解釋一下。 以一個簡單的串行流水線寄存器為例

轉:聊聊同步、異步、阻塞阻塞

AI strong 什麽 商業 同步與異步 好的 等待 不難 兩個 轉載:https://www.jianshu.com/p/aed6067eeac9 近來遇到了一些常見的概念,尤其是網絡編程方面的概念,如:阻塞、非阻塞、異步I/O等等,對於這些概念自己也沒有太清晰的認

關於flock文件鎖的阻塞阻塞

open bsp 等待 fopen pan ech 直接 else 阻塞與非阻塞 阻塞模式,程序會一直等待。 <?php $fp = fopen("lock.txt", "r"); if(flock($fp,LOCK_EX)) { //code flock($fp,

Java 同步異步-阻塞阻塞理解

blog markdown logs 任務 一段 mar 慢操作 兩個 需要 Java 同步與異步-阻塞與非阻塞理解 Java 中同步與異步,阻塞與非阻塞都是用來形容交互方式,區別在於它們描述的是交互的兩個不同層面。 同步與異步 同步與異步更關註交互雙方是否可以同時工作。以

redux-saga generator巢狀執行的阻塞阻塞

1.generator呼叫generator 在one中yield另一個generatoranother function*another(params){ // ... } function*one(params,{ call, put }){ // ...

圖解阻塞阻塞&同步非同步

一、阻塞I/O模型 二、非阻塞I/O模型 三、非同步I/O模型 四、同步I/O模型