多路IO复用与异步IO
多路IO復用與異步IO
- 同步阻塞IO(BIO)與同步非阻塞IO(NIO)
- 同步阻塞IO
- 同步非阻塞IO
- 多路IO復用
- select()函數使用示例
- 代碼演示
- poll()函數使用示例
- 代碼演示
- 異步IO
- 代碼演示
什么時多路IO復用? 多路IO復用是一種同步IO模型,,它可以實現一個線程可以同時監視多個文件描述符,一旦有某個文件描述符準備就緒,就會通知應用程序,對該文件描述符進行操作。在監視的各個文件描述符沒有準備就緒的時候,應用程序線程就會阻塞,交出cpu,讓cpu去執行其他的任務,以此提高cpu的利用率。
同步阻塞IO(BIO)與同步非阻塞IO(NIO)
同步阻塞IO
關于同步阻塞IO可以打個比方就是我們要讀取鍵盤和鼠標但是由于read()函數的阻塞作用導致我們只能讀取按照程序編寫的讀取順序來讀取兩個設備的數據,因為如果read()函數正在阻塞讀取鍵盤數據,但是此時我們沒有鍵盤輸入,去動鼠標,鼠標就會返回數據,但是由于read()函數阻塞在了鍵盤讀取上,所以我們就錯過了讀取鼠標數據的機會。
同步非阻塞IO
而同步非阻塞則是在一個while()循環里面使用設置了非阻塞的read()函數讀取鍵盤和鼠標數據,如果沒有讀取到數據就會立即返回錯誤,然后繼續讀取鼠標和鍵盤,直到兩個設備有數據來就會成功讀取到數據。
多路IO復用
單線程使用select()/poll()等系統調用實現對多個文件句柄的監視,如果有某個文件句柄的事件發生就會返回,沒有的話就會阻塞等待,單其實select()和poll()都是表現為外部阻塞式,內部非阻塞式自動輪詢多路阻塞式IO。
select()函數使用示例
單個線程打開的FD是有限的,通常默認是1024個,可以通過FD_SETSIZE設置
每次調用select()都需要把fd集合從用戶態拷貝到內核態,在需要輪詢的fd很多時,會造成較大的性能開銷。
select()前面提到了select()是通過輪詢掃描檢測事件有沒有發生的所以執行效率比較低。
代碼演示
在設置了select()函數的超時時間后,當函數超時后就會返回,后面再次執行到select()函數時,select()并不會阻塞了,不管有沒有監視的文件句柄事件發生,select()函數都會返回超時結果。
也可應個select()的時間設置參數地址給NULL,這樣select()函數就會不斷地監視文件句柄。
poll()函數使用示例
poll()函數與select()函數一樣每次調用都需要把fd集合從用戶態拷貝到內核態,在需要輪詢的fd很多時,會造成較大的性能開銷。
poll()對文件句柄的監視也是和select()函數一樣采用線性掃描的方式進行輪詢,所以在高并發的情況下效率也是比較底下的。
但是poll()與select()不同的一點就是poll沒有監視數量的限制
代碼演示
在poll的使用過程中當程序開始運行等待超時后,如果發生IO事件后還能夠檢測到,但是當檢測到IO事件和poll()就不會再超時了,就會一直等待監聽事件的發生。這一點和select()有所不同,select()超時后就不在監聽IO事件的發生了,而是一直返回超時。
#include<stdio.h> #include<stdlib.h> #include<string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <sys/time.h> #include <signal.h> #include <poll.h>int main(void) {int fd=-2;char buf[20];struct pollfd pfd[2]={0}; //監視兩個文件句柄所以定義了一個結構體數組bzero(buf,sizeof(buf));fd=open("/dev/input/mouse0",O_RDONLY);if (fd<0){perror("open:");}printf("already read\n");pfd[0].fd=0; //監視的文件描述符pfd[0].events=POLLIN; //設置為監視讀取事件pfd[1].fd=fd;pfd[1].events=POLLIN; while (1){int ret=poll(pfd,fd+1,1000);if (ret<0){perror("why");}else if (ret==0){printf("等待超時\n");}else{if(pfd[0].events==pfd[0].revents) //判斷是否為監視的事件發生{bzero(buf,sizeof(buf));read(0,buf,5);printf("read keyboard data=%s\n",buf);}if (pfd[1].events==pfd[1].revents){bzero(buf,sizeof(buf));read(fd,buf,5);printf("read mouse data=%s\n",buf);}}}return 0; }異步IO
異步IO相當于系統內核為我們實現的一套軟件中斷程序,如下代碼中的function()函數就可以比喻為中斷服務函數。主程序在完成一些異步IO的初始化之后,在while()循環中檢測鍵盤的輸入,但是如果注冊了異步事件的IO事件發生,就會去執行異步任務函數,即獲取鼠標輸入的數據。
代碼演示
#include<stdio.h> #include<stdlib.h> #include<string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <signal.h> int fd=0; void function(int sig) {char buf[5]={0};if (sig!=SIGIO){return;}else{read(fd,buf,sizeof(buf));printf("read mouse data=%s\n",buf);} }int main(void) {char buf[20];int flag=-1;bzero(buf,sizeof(buf));fd=open("/dev/input/mouse0",O_RDONLY);if (fd<0){perror("open:");}printf("already read\n");//把鼠標的文件描述符設置為可以接收一部IOflag=fcntl(fd,F_GETFL);flag|=O_ASYNC;fcntl(fd,F_SETFL,flag);//把異步IO事件的接收進程設置為當前進程fcntl(fd,F_SETOWN,getpid());//注冊當前進程的SINGIO信號捕獲函數signal(SIGIO,function);while (1){memset(buf,0,sizeof(buf));read(0,buf,sizeof(buf));printf("read keynoard =%s\n",buf);}return 0; }總結
以上是生活随笔為你收集整理的多路IO复用与异步IO的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python画蜡烛致敬烈士_「」matp
- 下一篇: dw网页设计期末设计一个网页_Dream