在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 }

 

内容来源于网络如有侵权请私信删除
你还没有登录,请先登录注册
  • 还没有人评论,欢迎说说您的想法!

相关课程

3536 9.8元 98元 1折