并发式IO的解决方案:多路非阻塞式IO、多路复用…
2018-06-18 04:11:12来源:未知 阅读 ()
在Linux应用编程中的并发式IO的三种解决方案是:
(1) 多路非阻塞式IO
(2) 多路复用
(3) 异步IO
以下代码将以操作鼠标和键盘为实例来演示。
1. 多路非阻塞式IO
多路非阻塞式IO访问,主要是添加O_NONBLOCK标志和fcntl()函数。
代码示例:
1 /* 2 * 并发式IO的解决方案1:多路非阻塞式IO处理键盘和鼠标同时读取 3 */ 4 5 #include <stdio.h> 6 #include <unistd.h> 7 #include <string.h> 8 #include <fcntl.h> 9 #include <sys/types.h> 10 #include <sys/stat.h> 11 12 #define MOUSEPATH "/dev/input/mouse1" 13 14 int main(void) 15 { 16 int fd = -1; 17 int ret = -1; 18 int flag = -1; 19 char buf[200] = {0}; 20 21 fd = open(MOUSEPATH, O_RDONLY | O_NONBLOCK); 22 if (fd < 0) 23 { 24 perror("open"); 25 _exit(-1); 26 } 27 28 // 把0的文件描述符变成非阻塞式的 29 flag = fcntl(0, F_GETFD); // 获取stdin原来的flag 30 flag |= O_NONBLOCK; // 给stdin原来的flag添加非阻塞式属性 31 fcntl(0, F_SETFL, flag); // 更新flag 32 33 while (1) 34 { 35 // 读鼠标 36 memset(buf, 0, sizeof(buf)); 37 ret = read(fd, buf, 50); 38 39 if (ret > 0) 40 { 41 printf("鼠标读出的内容是:[%s]\n", buf); 42 } 43 44 // 读键盘 45 memset(buf, 0, sizeof(buf)); 46 ret = read(0, buf, 50); 47 if (ret > 0) 48 { 49 printf("键盘读出的内容是:[%s]\n", buf); 50 } 51 } 52 53 return 0; 54 }
2. IO多路复用
(1) 多路非阻塞式IO
(2) select() 和 poll() 函数
(3) 外部式阻塞,内部非阻塞式自动轮询多路阻塞式IO
代码示例:
select() 函数实现:
1 /* 2 * 并发式IO的解决方案2:多路复用select()函数处理 3 */ 4 5 #include <stdio.h> 6 #include <string.h> 7 #include <unistd.h> 8 #include <sys/types.h> 9 #include <sys/stat.h> 10 #include <fcntl.h> 11 #include <sys/select.h> 12 #include <sys/time.h> 13 #include <stdlib.h> 14 15 #define MOUSEPATH "/dev/input/mouse1" 16 17 int main(void) 18 { 19 int fd = -1, ret = -1; 20 char buf[300] = {0}; 21 fd_set myset; 22 struct timeval tmv; 23 24 fd = open(MOUSEPATH, O_RDONLY); 25 if (-1 == fd) 26 { 27 perror("open"); 28 _exit(-1); 29 } 30 31 // 处理myset 32 FD_ZERO(&myset); // 清零 33 FD_SET(fd, &myset); // 加载鼠标的文件描述符到myset集合中 34 FD_SET(0, &myset); 35 36 // struct timeval *timeout 超时处理 37 tmv.tv_sec = 10; 38 tmv.tv_usec = 0; 39 40 // 原型:int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); 41 ret = select(fd+1, &myset, NULL, NULL, &tmv); // fd+1 这里是最大的fd加1 nfds是从0开始的 42 if (ret < 0) 43 { 44 perror("select"); 45 _exit(-1); 46 } 47 else if (ret == 0) 48 { 49 printf("Timeout.\n"); 50 exit(0); 51 } 52 else 53 { 54 /* 等到了一路IO,然后去监测哪个IO到了就处理哪个IO */ 55 if ( FD_ISSET(fd, &myset) ) 56 { 57 // 这里处理鼠标 58 memset(buf, 0, sizeof(buf)); 59 read(fd, buf, 50); 60 printf("鼠标读出的内容是:[%s]\n", buf); 61 } 62 63 if ( FD_ISSET(0, &myset) ) 64 { 65 // 这里处理键盘 66 memset(buf, 0, sizeof(buf)); 67 read(0, buf, 50); 68 printf("键盘读出的内容是:[%s]\n", buf); 69 } 70 } 71 72 return 0; 73 }
poll() 函数实现:
1 /* 2 * 并发式IO的解决方案2:多路复用poll()函数处理 3 */ 4 5 #include <stdio.h> 6 #include <string.h> 7 #include <unistd.h> 8 #include <sys/types.h> 9 #include <sys/stat.h> 10 #include <fcntl.h> 11 #include <poll.h> 12 #include <stdlib.h> 13 14 #define MOUSEPATH "/dev/input/mouse1" 15 #define IO_MULTIPLEXING 2 16 #define MAXBUF 1024 17 #define MILLISECOND 1000 18 19 int main(void) 20 { 21 int fd = -1, ret = -1, i = 0; 22 char buf[MAXBUF] = {0}; 23 struct pollfd pfd[IO_MULTIPLEXING] = {0}; 24 25 fd = open(MOUSEPATH, O_RDONLY); 26 if (-1 == fd) 27 { 28 perror("open"); 29 _exit(-1); 30 } 31 32 // 初始化 pollfd 33 pfd[0].fd = 0; // 键盘 34 pfd[0].events = POLLIN; // 等待读操作 35 36 pfd[1].fd = fd; // 键盘 37 pfd[1].events = POLLIN; // 等待读操作 38 39 // 原型:int poll(struct pollfd *fds, nfds_t nfds, int timeout); 40 ret = poll(pfd, fd+1, 10 * MILLISECOND); // fd+1 这里是最大的fd加1 nfds是从0开始的 41 if (ret < 0) 42 { 43 perror("poll"); 44 _exit(-1); 45 } 46 else if (ret == 0) 47 { 48 printf("Timeout.\n"); 49 exit(0); 50 } 51 else 52 { 53 /* 等到了一路IO,然后去监测哪个IO到了就处理哪个IO */ 54 for (i = 0; i < IO_MULTIPLEXING; i++) 55 { 56 // 处理键盘和鼠标 57 if ( pfd[i].events == pfd[i].revents ) 58 { 59 memset(buf, 0, sizeof(buf)); 60 read(pfd[i].fd, buf, MAXBUF); 61 printf("Content:[%s].\n", buf); 62 } 63 } 64 } 65 66 close(fd); 67 68 return 0; 69 }
3. 异步IO
(1) 异步IO:就是操作系统用软件实现的一套中断响应系统
(2) 工作方法:进程注册一个异步IO事件(使用signal注册一个信号SIGIO的处理函数)
(3) 涉及函数:fcntl(F_GETFL, F_SETFL, O_ASYNC, F_SETOWN), signal(), sigaction()函数
代码示例:
1 /* 2 * 并发式IO的解决方案3:异步IO处理 signal or sigaction and fcntl 3 */ 4 5 #include <stdio.h> 6 #include <sys/types.h> 7 #include <sys/stat.h> 8 #include <fcntl.h> 9 #include <unistd.h> 10 #include <signal.h> 11 #include <string.h> 12 13 #define MAXBUFF 1024 14 #define MOUSEPATH "/dev/input/mouse1" 15 16 // 全局变理 17 int mousefd = -1; 18 19 // 定义signal的函数指针 20 typedef void (*sighandler_t)(int); 21 22 // 函数声明 23 void func(int sig); 24 25 int main(void) 26 { 27 int flag = -1; 28 char buf[MAXBUFF]; 29 sighandler_t ret = (sighandler_t)-2; 30 31 // 操作鼠标文件 32 mousefd = open(MOUSEPATH, O_RDONLY); 33 if ( mousefd < 0 ) 34 { 35 perror("open"); 36 _exit(-1); 37 } 38 39 // 把鼠标的文件描述符设置为可以接受异步IO 40 flag = fcntl(mousefd, F_GETFL); 41 flag |= O_ASYNC; 42 fcntl(mousefd, F_SETFL, flag); 43 44 // 把异步IO事件的接收进程设置为当前进程 45 fcntl(mousefd, F_SETOWN, getpid()); 46 47 // 注册当前进程的SIGIO信号捕获函数 48 ret = signal(SIGIO, func); 49 if (SIG_ERR == ret) 50 { 51 perror("signal"); 52 _exit(-1); 53 } 54 55 // 操作键盘 56 while (1) 57 { 58 memset(buf, 0, sizeof(buf)); 59 read(0, buf, MAXBUFF); 60 printf("键盘读取的内容是:[%s].\n", buf); 61 } 62 63 return 0; 64 } 65 66 // 绑定到SIGIO信号,在函数内处理异步通知事件 67 void func(int sig) 68 { 69 char buf[MAXBUFF] = {0}; 70 71 if ( sig != SIGIO ) 72 return; 73 74 read(mousefd, buf, MAXBUFF); 75 printf("鼠标读取的内容是:[%s].\n", buf); 76 }
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇:写出这个数 (20)
下一篇:c语言是如何实现泛型链表
- C++程序崩溃解决方案 2019-12-04
- C++中操作符重载的概念 2019-05-23
- 多路分支----switch语句 2018-12-04
- B-树 C++模板类封装(有图有真相) 2018-06-27
- echarts legend 重叠 (转载) 2018-06-27
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash