高级IO(文件的读写)——并发式IO的解决方案(解决多路阻塞式IO的方案)
生活随笔
收集整理的這篇文章主要介紹了
高级IO(文件的读写)——并发式IO的解决方案(解决多路阻塞式IO的方案)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
以下內容源于朱有鵬《物聯網大講堂》課程的學習整理,如有侵權,請告知刪除。
一、并發式IO的解決方案
- 所謂并發式IO,即上節中提及的鼠標和鍵盤都已經啟動。
1、非阻塞式IO
- 使用fcntl函數, 將上節中阻塞式的鼠標和鍵盤讀取改為非阻塞式的。
- 性能不是很好。
#include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>int main(void) {// 讀取鼠標int fd = -1;int flag = -1;char buf[200];int ret = -1;fd = open("/dev/input/mouse1", O_RDONLY | O_NONBLOCK);if (fd < 0){perror("open:");return -1;}// 把0號文件描述符(stdin)變成非阻塞式的flag = fcntl(0, F_GETFL); // 先獲取原來的flagflag |= O_NONBLOCK; // 添加非阻塞屬性fcntl(0, F_SETFL, flag); // 更新flag// 這3步之后,0就變成了非阻塞式的了while (1){// 讀鼠標memset(buf, 0, sizeof(buf));ret = read(fd, buf, 50);if (ret > 0){printf("鼠標讀出的內容是:[%s].\n", buf);}// 讀鍵盤memset(buf, 0, sizeof(buf));ret = read(0, buf, 5);if (ret > 0){printf("鍵盤讀出的內容是:[%s].\n", buf);}}return 0; }/* int main(void) {// 讀取鼠標int fd = -1;char buf[200];fd = open("/dev/input/mouse1", O_RDONLY | O_NONBLOCK);if (fd < 0){perror("open:");return -1;}memset(buf, 0, sizeof(buf));printf("before read.\n");read(fd, buf, 50);printf("讀出的內容是:[%s].\n", buf);return 0; } *//* int main(void) {// 讀取鍵盤// 鍵盤就是標準輸入,stdinchar buf[100];int flag = -1;// 把0號文件描述符(stdin)變成非阻塞式的flag = fcntl(0, F_GETFL); // 先獲取原來的flagflag |= O_NONBLOCK; // 添加非阻塞屬性fcntl(0, F_SETFL, flag); // 更新flag// 這3步之后,0就變成了非阻塞式的了memset(buf, 0, sizeof(buf));printf("before read.\n");read(0, buf, 5);printf("讀出的內容是:[%s].\n", buf);return 0; } */
2、多路復用IO
3、異步通知(異步IO)
二、IO多路復用原理
1、何為IO多路復用?
(1)英文為:IO multiplexing
(2)用在什么地方?
- 用于解決并發式IO,多路阻塞式的。
(3)涉及select函數、poll函數。
- 兩個函數設計思想一樣,外部特征不一樣。
(4)實現原理:外部阻塞式(select函數本身是阻塞式的),內部非阻塞式自動輪詢(select自動輪詢時A,B)多路阻塞式IO(鍵盤A,鼠標B,這兩者本身是阻塞式的)。
- 只要AB至少有一個輸入,則select由阻塞返回。
2、select函數介紹
3、poll函數介紹
4、多路復用實踐
(1)用poll函數實現同時讀取鍵盤鼠標
#include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <poll.h>int main(void) {// 讀取鼠標int fd = -1, ret = -1;char buf[200];struct pollfd myfds[2] = {0};fd = open("/dev/input/mouse1", O_RDONLY);if (fd < 0){perror("open:");return -1;}// 初始化我們的pollfdmyfds[0].fd = 0; // 鍵盤myfds[0].events = POLLIN; // 等待讀操作myfds[1].fd = fd; // 鼠標myfds[1].events = POLLIN; // 等待讀操作ret = poll(myfds, fd+1, 10000);if (ret < 0){perror("poll: ");return -1;}else if (ret == 0){printf("超時了\n");}else{// 等到了一路IO,然后去監測到底是哪個IO到了,處理之if (myfds[0].events == myfds[0].revents){// 這里處理鍵盤memset(buf, 0, sizeof(buf));read(0, buf, 5);printf("鍵盤讀出的內容是:[%s].\n", buf);}if (myfds[1].events == myfds[1].revents){// 這里處理鼠標memset(buf, 0, sizeof(buf));read(fd, buf, 50);printf("鼠標讀出的內容是:[%s].\n", buf);}}return 0; }
(2)用select函數實現同時讀取鍵盤鼠標
- 設置超時時間,即阻塞的時間不能太長,如果很久都沒有IO來激活select,則表明超時了。
#include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/select.h> #include <sys/time.h>int main(void) {// 讀取鼠標int fd = -1, ret = -1;char buf[200];fd_set myset;struct timeval tm;//設置超時時間,即阻塞的時間不能太長,如果很久都沒有IO來激活select,則表明超時了。fd = open("/dev/input/mouse1", O_RDONLY);if (fd < 0){perror("open:");return -1;}// 當前有2個fd,一共是fd一個是0// 處理mysetFD_ZERO(&myset);FD_SET(fd, &myset);FD_SET(0, &myset);tm.tv_sec = 10;tm.tv_usec = 0;ret = select(fd+1, &myset, NULL, NULL, &tm);//+1,是因為0~fd,則共有fd+1個文件描述符if (ret < 0)//錯誤{perror("select: ");return -1;}else if (ret == 0)//表明超時{printf("超時了\n");}else//>0表示有一路IO激活了{// 等到了一路IO,然后去監測到底是哪個IO到了,處理之if (FD_ISSET(0, &myset)){// 這里處理鍵盤memset(buf, 0, sizeof(buf));read(0, buf, 5);printf("鍵盤讀出的內容是:[%s].\n", buf);}if (FD_ISSET(fd, &myset)){// 這里處理鼠標memset(buf, 0, sizeof(buf));read(fd, buf, 50);printf("鼠標讀出的內容是:[%s].\n", buf);}}return 0; }
三、異步IO
1、何為異步IO?
(1)幾乎可以認為,異步IO就是操作系統用軟件實現的一套中斷響應系統。類比硬件中斷。
(2)異步IO的工作方法
- 當前進程注冊一個異步IO事件(使用signal注冊一個信號SIGIO的處理函數),然后當前進程可以正常處理自己的事情;
- 當異步事件發生后,當前進程會收到一個SIGIO信號,從而執行綁定的處理函數,來處理這個異步事件。
2、涉及的函數
(1)fcntl函數,主要設置異步通知。
- 涉及的命令有F_GETFL(獲取flag)、F_SETFL、O_ASYNC(表明可以接收異步通知)、F_SETOWN(設置通知誰(一般都是通知當前進程));
(2)signal或sigaction函數(SIGIO)
3、代碼實踐
#include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <signal.h>int mousefd = -1;// 綁定到SIGIO信號,在函數內處理異步通知事件 void func(int sig) {char buf[200] = {0};if (sig != SIGIO)return;read(mousefd, buf, 50);printf("鼠標讀出的內容是:[%s].\n", buf); }int main(void) {// 讀取鼠標char buf[200];int flag = -1;mousefd = open("/dev/input/mouse1", O_RDONLY);if (mousefd < 0){perror("open:");return -1;} // 把鼠標的文件描述符設置為可以接受異步IOflag = fcntl(mousefd, F_GETFL);flag |= O_ASYNC;fcntl(mousefd, F_SETFL, flag);// 把異步IO事件的接收進程設置為當前進程fcntl(mousefd, F_SETOWN, getpid());// 注冊當前進程的SIGIO信號捕獲函數signal(SIGIO, func);// 讀鍵盤,在這里是當前進程while (1){memset(buf, 0, sizeof(buf));read(0, buf, 5);printf("鍵盤讀出的內容是:[%s].\n", buf);}return 0; }
四、存儲映射IO
1、反映在mmap函數
- 把一個文件和一段內存映射起來。比如LCD設備文件和顯存的對應。
2、例子
- LCD顯示,IPC之共享內存
3、存儲映射IO的特點
(1)共享而不是復制,減少內存操作。
(2)處理大文件時效率高(一般用于視頻處理),小文件不劃算。
總結
以上是生活随笔為你收集整理的高级IO(文件的读写)——并发式IO的解决方案(解决多路阻塞式IO的方案)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android 1024 github,
- 下一篇: 共轭梯度法粗浅理解