并发式IO的解决方案:多路非阻塞式IO、多路复用、异步IO

2016-12-23 18:51:40来源:cnblogs.com作者:Alarm人点击

在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原来的flag30     flag |= O_NONBLOCK;                // 给stdin原来的flag添加非阻塞式属性31     fcntl(0, F_SETFL, flag);        // 更新flag32     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     // 处理myset32     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     else53     {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        216 #define MAXBUF                102417 #define MILLISECOND            100018 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     // 初始化 pollfd33     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     else52     {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     // 把鼠标的文件描述符设置为可以接受异步IO40     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 }

 

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台