程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 並發式IO的解決方案:多路非阻塞式IO、多路復用、異步IO,多路復用io

並發式IO的解決方案:多路非阻塞式IO、多路復用、異步IO,多路復用io

編輯:關於C語言

並發式IO的解決方案:多路非阻塞式IO、多路復用、異步IO,多路復用io


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

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved