高级IO(文件的读写)——并发式IO的解决方案(解决多路阻塞式IO的方案)
来源:互联网 发布:国家药监局数据查询 编辑:程序博客网 时间:2024/06/06 18:46
以下内容源于朱有鹏《物联网大讲堂》课程的学习整理,如有侵权,请告知删除。
一、并发式IO的解决方案
- 所谓并发式IO,即上节中提及的鼠标和键盘都已经启动。
1、非阻塞式IO
- 使用fcntl函数, 将上节中阻塞式的鼠标和键盘读取改为非阻塞式的。
- 性能不是很好。
#include <stdio.h>#include <unistd.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>int main(void){// 读取鼠标int fd = -1;int flag = -1;char buf[200];int ret = -1;fd = open("/dev/input/mouse1", O_RDONLY | O_NONBLOCK);if (fd < 0){perror("open:");return -1;}// 把0号文件描述符(stdin)变成非阻塞式的flag = fcntl(0, F_GETFL);// 先获取原来的flagflag |= O_NONBLOCK;// 添加非阻塞属性fcntl(0, F_SETFL, flag);// 更新flag// 这3步之后,0就变成了非阻塞式的了while (1){// 读鼠标memset(buf, 0, sizeof(buf));ret = read(fd, buf, 50);if (ret > 0){printf("鼠标读出的内容是:[%s].\n", buf);}// 读键盘memset(buf, 0, sizeof(buf));ret = read(0, buf, 5);if (ret > 0){printf("键盘读出的内容是:[%s].\n", buf);}}return 0;}/*int main(void){// 读取鼠标int fd = -1;char buf[200];fd = open("/dev/input/mouse1", O_RDONLY | O_NONBLOCK);if (fd < 0){perror("open:");return -1;}memset(buf, 0, sizeof(buf));printf("before read.\n");read(fd, buf, 50);printf("读出的内容是:[%s].\n", buf);return 0;}*//*int main(void){// 读取键盘// 键盘就是标准输入,stdinchar buf[100];int flag = -1;// 把0号文件描述符(stdin)变成非阻塞式的flag = fcntl(0, F_GETFL);// 先获取原来的flagflag |= O_NONBLOCK;// 添加非阻塞属性fcntl(0, F_SETFL, flag);// 更新flag// 这3步之后,0就变成了非阻塞式的了memset(buf, 0, sizeof(buf));printf("before read.\n");read(0, buf, 5);printf("读出的内容是:[%s].\n", buf);return 0;}*/
2、多路复用IO
3、异步通知(异步IO)
二、IO多路复用原理
1、何为IO多路复用?
(1)英文为:IO multiplexing
(2)用在什么地方?
- 用于解决并发式IO,多路阻塞式的。
(3)涉及select函数、poll函数。
- 两个函数设计思想一样,外部特征不一样。
(4)实现原理:外部阻塞式(select函数本身是阻塞式的),内部非阻塞式自动轮询(select自动轮询时A,B)多路阻塞式IO(键盘A,鼠标B,这两者本身是阻塞式的)。
- 只要AB至少有一个输入,则select由阻塞返回。
2、select函数介绍
3、poll函数介绍
4、多路复用实践
(1)用poll函数实现同时读取键盘鼠标
#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;}// 初始化我们的pollfdmyfds[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;}
(2)用select函数实现同时读取键盘鼠标
- 设置超时时间,即阻塞的时间不能太长,如果很久都没有IO来激活select,则表明超时了。
#include <stdio.h>#include <unistd.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <sys/select.h>#include <sys/time.h>int main(void){// 读取鼠标int fd = -1, ret = -1;char buf[200];fd_set myset;struct timeval tm;//设置超时时间,即阻塞的时间不能太长,如果很久都没有IO来激活select,则表明超时了。fd = open("/dev/input/mouse1", O_RDONLY);if (fd < 0){perror("open:");return -1;}// 当前有2个fd,一共是fd一个是0// 处理mysetFD_ZERO(&myset);FD_SET(fd, &myset);FD_SET(0, &myset);tm.tv_sec = 10;tm.tv_usec = 0;ret = select(fd+1, &myset, NULL, NULL, &tm);//+1,是因为0~fd,则共有fd+1个文件描述符if (ret < 0)//错误{perror("select: ");return -1;}else if (ret == 0)//表明超时{printf("超时了\n");}else//>0表示有一路IO激活了{// 等到了一路IO,然后去监测到底是哪个IO到了,处理之if (FD_ISSET(0, &myset)){// 这里处理键盘memset(buf, 0, sizeof(buf));read(0, buf, 5);printf("键盘读出的内容是:[%s].\n", buf);}if (FD_ISSET(fd, &myset)){// 这里处理鼠标memset(buf, 0, sizeof(buf));read(fd, buf, 50);printf("鼠标读出的内容是:[%s].\n", buf);}}return 0;}
三、异步IO
1、何为异步IO?
(1)几乎可以认为,异步IO就是操作系统用软件实现的一套中断响应系统。类比硬件中断。
(2)异步IO的工作方法
- 当前进程注册一个异步IO事件(使用signal注册一个信号SIGIO的处理函数),然后当前进程可以正常处理自己的事情;
- 当异步事件发生后,当前进程会收到一个SIGIO信号,从而执行绑定的处理函数,来处理这个异步事件。
2、涉及的函数
(1)fcntl函数,主要设置异步通知。
- 涉及的命令有F_GETFL(获取flag)、F_SETFL、O_ASYNC(表明可以接收异步通知)、F_SETOWN(设置通知谁(一般都是通知当前进程));
(2)signal或sigaction函数(SIGIO)
3、代码实践
#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;}// 把鼠标的文件描述符设置为可以接受异步IOflag = 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));read(0, buf, 5);printf("键盘读出的内容是:[%s].\n", buf);}return 0;}
四、存储映射IO
1、反映在mmap函数
- 把一个文件和一段内存映射起来。比如LCD设备文件和显存的对应。
2、例子
- LCD显示,IPC之共享内存
3、存储映射IO的特点
(1)共享而不是复制,减少内存操作。
(2)处理大文件时效率高(一般用于视频处理),小文件不划算。
阅读全文
0 0
- 高级IO(文件的读写)——并发式IO的解决方案(解决多路阻塞式IO的方案)
- 并发式IO的解决方案---非阻塞式、多路复用和异步通知(异步IO)
- 并发式IO的解决方案
- 高级IO(文件的读写)——阻塞式IO的困境、非阻塞式IO
- Linux文件IO(文件的读写)
- 阻塞IO和非阻塞IO的区别(转载)
- NIO和阻塞io的读写文件效率差异
- 阻塞IO、非阻塞IO的区别
- IO流的文件读写
- IO对文件的读写
- 文件的读写,io流
- 阻塞式IO的困境
- 阻塞IO的理解
- IO与文件读写---同步/异步与阻塞/非阻塞的区别(转) _适用于TI dsp驱动
- 五种IO 模式——阻塞(默认IO模式),非阻塞(常用语管道),IO多路复用(IO多路复用的应用场景),信号IO,异步IO
- 五种IO 模式——阻塞(默认IO模式),非阻塞(常用语管道),IO多路复用(IO多路复用的应用场景),信号IO,异步IO
- 五种IO 模式——阻塞(默认IO模式),非阻塞(常用语管道),IO多路复用(IO多路复用的应用场景),信号IO,异步IO
- 五种IO 模式——阻塞(默认IO模式),非阻塞(常用语管道),IO多路复用(IO多路复用的应用场景),信号IO,异步IO
- Mysql锁及事务的隔离水平
- 算法系列——Longest Substring Without Repeating Characters
- android获取短信的内容
- 关于精灵图
- lua 人机交互(二)
- 高级IO(文件的读写)——并发式IO的解决方案(解决多路阻塞式IO的方案)
- 反射、代理学习笔记
- Unity3D Attributes用法小结(一)
- Python :滑动窗口的最大值
- Latex 论文elsevier,手把手如何用Latex写论文
- 使用Sqoop将数据从Hive导入MySQL可能遇到的问题
- 4298. 【NOIP2015模拟11.2晚】我的天
- 尺寸相关属性
- 【Java核心计算 基础知识(第9版)】第3章 Java的基本程序设计结构