高级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
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 京东第三方店铺关闭怎么办 京东店铺关门了怎么办 国美退款不到账怎么办 小米小店通过了怎么办 苹果的发票丢了怎么办 苹果7p开不开机怎么办 申请退款了怎么卖家还发货怎么办 买家申请退款卖家不退款怎么办 卖家恶意不退款怎么办 欠条到期了对方不还钱怎么办 冰箱磕了一坑怎么办 办信用卡没有家庭地址的怎么办 钱付了货没收到怎么办 在苏宁易购上买东西地址错了怎么办 手机分期付款银行卡丢了怎么办 华硕笔记本鼠标不动了怎么办 韵达快递不派送怎么办 中通快递不派送怎么办 农业银行信用卡密码输错三次怎么办 农业银行卡多次输错密码怎么办 想把店长弄走怎么办 济南银座卡过期了怎么办 银座购物卡丢失后怎么办 银座的卡丢了怎么办 银行卡换了旧卡怎么办 大理市民卡丢了怎么办 市民卡内的钱怎么办 宝付支付乱扣款怎么办 苏宁任性贷逾期怎么办 第二次跟家里开口要钱还网贷怎么办 网贷到家来要钱怎么办 网贷贷不了啦急要钱怎么办 百度推广竞价关键词太长怎么办 药店位置差客流少怎么办 网站上的用词违规怎么办 苹果16g内存不够怎么办 手机16g内存不够怎么办 在私企年纪大了怎么办 谷歌浏览器显示不安全打不开怎么办 4s密码多次错误怎么办 苹果4s手机系统错误怎么办