高級IO——異步IO


回顧同時讀鍵盤、鼠標的方法

①多進程                                                參考:高級IO——非阻塞IO

②多線程              參考:高級IO——非阻塞IO

③將“讀鼠標”和“讀鍵盤”設置為非阻塞 參考:高級IO——非阻塞IO

④多路IO(select、poll機制)    參考:高級IO——多路IO

⑤異步IO

③④都是單線的

異步IO的原理

①~④都是主動的去讀,對於read函數來說它並不知道是不是一定有數據,如果有數據就讀到數據,沒有數據要么阻塞直到讀到數據為止,要么就不阻塞。實際上除了以上描述的方式外,還有另外一種聰明的方式,那就是使用異步IO的方式來實現。異步IO的原理就是,底層把數據准備好后,內核就會給進程發送一個“異步通知的信號”通知進程,表示數據准備好了,然后調用信號處理函數去讀數據,在沒有准備好時,進程忙自己的事情。比如使用異步IO讀鼠標,底層鼠標驅動把數據准備好后,會發一個“SIGIO”(異步通知信號)給進程,進程調用捕獲函數讀鼠標,讀鼠標的SIGIO捕獲函數需要我們自己定義。

舉個例子:到吃飯時間了,你可以去飯店排隊買飯,也可以提前給老板打電話,飯做好了叫我過去吃

使用異步IO方式讀鼠標和鍵盤

進程正常阻塞讀鍵盤,然后將讀鼠標設置為異步IO方式。進程正常阻塞讀鍵盤時,如果鼠標沒有數據的話,進程不關心讀鼠標的事情,如果鼠標數據來了,底層鼠標驅動就會向進程發送一個SIGIO信號,然后調用注冊的SIGIO信號捕獲函數讀鼠標數據。當然也可以反過來,進程正常阻塞讀鼠標,然后將讀鍵盤設置為異步IO方式。

異步IO這個名字怎么理解?

:比如以異步IO方式讀鼠標數據為例,如果知道什么時間數據會來,等這個時間到時再去讀數據,這就是步調統一的同步讀。如果不知道什么時候會有數據來,這種就只能是什么時候數據來了就什么時候讀,這種就是異步的讀。之所叫異步,是因為我不知道你什么時候來,沒辦法統一步調(異步的),只能是隨時來是隨時讀。  

不過使用異步IO有兩個前提:

(1)底層驅動必須要有相應的發送SIGIO信號的代碼,只有這樣當底層數據准備好后,底層才會發送SIGIO信號給進程。我們之所以可以對鼠標設置異步IO,是因為人家在實現鼠標驅動時,有寫發送SIGIO信號的代碼,如果驅動程序是我們自己寫的,發送SIGIO的代碼就需要我們自己來寫。

(2)應用層必須進行相應的異步IO的設置,否者無法使用異步IO應用層進行異步IO設置時,使用的也是fcntl函數。

使用異步IO時,應用層的設置步驟

①調用signal函數對SIGIO信號設置捕獲函數。在捕獲函數里面實現讀操作,比如讀鼠標。

②使用fcntl函數,將接收SIGIO信號的進程設置為當前進程。如果不設置的,底層驅動並不知道將SIGIO信號發送給哪一個進程。

fcntl(mousefd, F_SETOWN, getpid());

③使用fcntl函數,對文件描述符增設O_ASYNC的狀態標志,讓fd支持異步IO

mouse_fd = open("/dev/input/mouse1", O_RDONLY);                     
flag = fcntl(mouse_fd, F_GETFL);
flag |= O_ASYNC;    //補設O_ASYNC
fcntl(mouse_fd, F_SETFL, flag);
View Code

代碼演示

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <unistd.h>
 4 #include <string.h>
 5 #include <strings.h>
 6 #include <errno.h>
 7 #include <sys/time.h>
 8 #include <sys/types.h>
 9 #include <unistd.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <fcntl.h>
13 #include <poll.h>
14 #include <signal.h>
15 
16 void print_err(char *str, int line, int err_no)
17 {
18         printf("%d, %s: %s\n", line, str, strerror(err_no));
19         exit(-1);
20 }
21 
22 int mousefd = 0;
23 void signal_fun(int signo)
24 {
25     int buf;
26     int ret = 0;
27 
28     if(SIGIO == signo)
29     {
30         bzero(&buf, sizeof(buf));
31         ret = read(mousefd, &buf, sizeof(buf));
32         if(ret > 0) printf("%d\n", buf);
33     }
34 }
35 
36 int main(void)
37 {
38     int ret = 0;
39     char buf[100] = {0};
40     struct pollfd fds[2];
41     
42     mousefd = open("/dev/input/mouse0", O_RDONLY);
43     if(mousefd == -1) print_err("open mouse0 fail", __LINE__, errno);
44         
45     //為SIGIO設置捕獲函數,在捕獲函數里面讀鼠標    
46     signal(SIGIO, signal_fun);
47     
48     //告訴鼠標驅動,他發送的SIGIO信號由當前進程接收
49     fcntl(mousefd, F_SETOWN, getpid());    
50 
51     //對mousefd進行設置,讓其支持異步IO
52     int flg = fcntl(mousefd, F_GETFL);
53     flg |= O_ASYNC;
54     fcntl(mousefd, F_SETFL, flg);
55     
56     while(1)
57     {
58         bzero(buf, sizeof(buf));
59         ret = read(0, buf, sizeof(buf));
60         if(ret > 0) printf("%s\n", buf);
61     }
62 
63     return 0;
64 }
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM