高级IO
例:同时读取鼠标与键盘
传统情况下,由于阻塞只能同时读取一路。
解决方案
1.非阻塞IO
2.异步IO
3.IO多路复用
非阻塞IO
使用O_NONBLOCK和fcntl实现非阻塞
#include <stdio.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main() { int fd = -1; int flag = -1; int ret = -1; //把0号文件描述符(stdin)变为非阻塞 flag = fcntl(0,F_GETFL); flag |= O_NONBLOCK; fcntl(0, F_SETFL, flag);//设置为非阻塞 fd = open("/dev/input/mouse1", O_RDONLY|O_NONBLOCK); if(fd < 0) { perror("open"); exit(-1); } char buf[100]; //读鼠标 while(1) { memset(buf , 0, sizeof(buf)); ret = read(fd , buf , 100); if(ret > 0) { printf("鼠标读取的内容:[%s]\n" , buf); } memset(buf , 0, sizeof(buf)); ret = read(0 , buf , 100); if(ret > 0) { printf("键盘读取的内容:[%s]\n" , buf); } } return 0; }
异步IO
使用select和poll实现异步IO
特点为外部阻塞式,内部非阻塞式自动轮询多路阻塞式IO
#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; } // 初始化我们的pollfd myfds[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; }
异步IO
通过信号实现
异步IO的工作方法是:我们当前进程注册一个异步IO事件(使用signal注册一个信号SIGIO的处理函数),然后当前进程可以正常处理自己的事情,当异步事件发生后当前进程会收到一个SIGIO信号从而执行绑定的处理函数去处理这个异步事件。
涉及的函数:
(1)fcntl(F_GETFL、F_SETFL、O_ASYNC、F_SETOWN)
(2)signal或者sigaction(SIGIO)
#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; } // 把鼠标的文件描述符设置为可以接受异步IO flag = 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)); //printf("before 键盘 read.\n"); read(0, buf, 5); printf("键盘读出的内容是:[%s].\n", buf); } return 0; }
存储映射IO
1、mmap函数
2、LCD显示和IPC之共享内存
3、存储映射IO的特点
(1)共享而不是复制,减少内存操作
(2)处理大文件时效率高,小文件不划算