高级IO(文件的读写)——并发式IO的解决方案(解决多路阻塞式IO的方案)
以下内容源于朱有鹏《物联网大讲堂》课程的学习整理,如有侵权,请告知删除。
一、并发式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)处理大文件时效率高(一般用于视频处理),小文件不划算。
高级IO(文件的读写)——并发式IO的解决方案(解决多路阻塞式IO的方案)相关推荐
- 高级IO(文件的读写)——阻塞式IO的困境、非阻塞式IO
以下内容源于朱有鹏<物联网大讲堂>课程的学习整理,如有侵权,请告知删除. 一.阻塞式IO的困境 1.程序中读取键盘 int main(void) {// 读取键盘// 键盘就是标准输入,s ...
- AIO,BIO,NIO:同步阻塞式IO,同步非阻塞IO,异步非阻塞IO
BIO,同步阻塞式IO,简单理解:一个连接一个线程 NIO,同步非阻塞IO,简单理解:一个请求一个线程 AIO,异步非阻塞IO,简单理解:一个有效请求一个线程 IO:阻塞IO BIO:同步阻塞IO.服 ...
- 从阻塞式IO到epoll——IO精讲
Linux虚拟文件系统的理解 VFS 是一棵树, 树上的节点可以映射到对应的物理位置 与之对应的,什么是实际上的文件系统呢,比如说Windows操作系统上的,D盘对应的就是那块磁盘,C盘对应的就是这块 ...
- 阻塞式IO和非阻塞式IO
什么是阻塞式IO,什么是非阻塞式IO?区分他们有何用? 阻塞式IO:IO即input/output,阻塞式IO指的是"一旦输入/输出工作没有完成,则程序阻塞,直到输入/输出工作完成" ...
- 五种网络IO模型:阻塞式IO 非阻塞式IO IO复用(IO multiplexing) 信号驱动式IO 异步IO
文章目录 五种网络IO模型 举例说明 阻塞式I/O模型 非阻塞式I/O I/O多路复用 信号驱动式I/O 异步I/O 比较结果 总结 同步 异步 阻塞 非阻塞 阻塞/非阻塞: 同步/异步: 举例子:小 ...
- Servlet3.1 新增的非阻塞式IO
Servlet3.1新增的新特性 强制更改sessionId 由HttpServletRequest 的changeSessionId()方法实现 非阻塞式IO 非阻塞式IO 我们应该知道Servle ...
- 服务端thrift 使用非阻塞式IO报异常Got an IOException in internalRead!
参考:https://blog.csdn.net/z13192905903/article/details/103181204 参考:https://blog.csdn.net/xmtblog/art ...
- Python之IO模式 阻塞式io 非阻塞io 多路复用io 异步io 信号驱动io
参考:https://www.cnblogs.com/alex3714/articles/5248247.html 提高:http://www.cnblogs.com/alex3714/article ...
- Java.IO 字符流读写文件
点击上方 IT牧场 ,选择 置顶或者星标 技术干货每日送达! 一.序 上一篇我们谈了 java.IO 文件字节流读写操作(能懂系列Java.io文件字节流读写)大家应该都很熟悉了.但是中文和英文在字符 ...
最新文章
- .NET Core也可以使用MongoDB了
- 如何从几何角度上理解方程组只有一个解_深度科普---电磁波(三):无激励下的真空中的Maxwell方程组的解...
- 在NPP运行Python报错:SyntaxError: Non-ASCII character '\xe5' in file的解决方法
- python编程(python和c相互调用)
- 练打字-测试看图说话(AD安装)
- html二维坐标系转换,旋转坐标系 转换工具
- STORM的三种事务
- java 不同时区时间转换_Java中的时区转换小结
- Fireworks-CS5入门到高级129讲视频教程
- 聚类分析 距离 matlab,matlab聚类分析_matlab
- 修改了DNS服务器网速慢,网络速度缓慢怎么办?轻松一键修改DNS设置让网速提升五倍...
- 论文阅读 (54):DeepFool: A Simple and Accurate Method to Fool Deep Neural Networks
- 沧海桑田:Linux 系统启动的演进模型与发展变化
- 《人生的智慧》-叔本华著[韦启昌-(译)]
- illumina 二代测序原理及过程
- 便利贴--25{uniapp移动端滑动模块-因为uniapp打包后没有window,所以要另外去做监听和触控事件的传递}
- 如何阅读数据手册datasheet
- 不要被假相迷惑-有意思的声卡驱动
- 这所年轻大学,被誉为中国离科学最近的大学!
- 结构体练习——青蛙吃蚊子
热门文章
- 前端框架开始学习Vue(一)
- 【LA3415 训练指南】保守的老师 【二分图最大独立集,最小割】
- Git的GUI工具sourcetree的使用
- javascript 反斜杠\
- [转]基于图的机器学习技术:谷歌众多产品和服务背后的智能
- imgareaselect 缩略图 裁剪图片
- [18]Debian Linux Install GNU GCC Compiler and Development Environment
- [译] 论 Rust 和 WebAssembly 对源码地址索引的极限优化
- 学习API HOOK,编写了一个winsock 的封包抓取程序,可免费使用;
- Oracle 存储过程错误之PLS-00201: 必须声明标识符