当前位置:网站首页>高效IO模型
高效IO模型
2022-08-04 03:05:00 【秃头宇】
文章目录
前言
IO过程总体分为两步,第一步等:接收端->接受缓冲区等待数据的递达,发送端->等待发送缓冲区有可用空间,将发送数据放入发送缓冲区;第二步拷贝:接收端->将递达的数据从内核空间拷贝到用户空间的接受缓冲区,发送端->将发送的数据从用户空间的发送缓冲区拷贝至内核缓冲区;
所以高效IO本质是单位时间内拷贝的频率很高,重点是缩短等待的时间
一、五种IO模型
1.1 阻塞IO
阻塞IO是最常见的IO模型(在内核将数据准备好之前,系统调用会一直等待,所有的套接字,默认都是阻塞方式)
阻塞:本质是由OS发起,由OS执行,进程状态R->(S or T or D),进入等待队列当中,数据就绪后,进程被操作系统唤醒,再去执行
recvfrom
1.2 非阻塞IO
如果内核还未将数据准备好,系统调用仍然会直接返回,并且返回EWOULDBLOCK
非阻塞IO往往需要程序员循环的方式反复尝试读写文件描述符, 这个过程称为轮询. 这对CPU来说是较大的浪费, 一般只有特定场景下才使用
非阻塞轮询的本质是:由用户发起,OS执行,做事件就绪(OS有数据)的检测工作
1.3 信号驱动IO
内核将数据准备好的时候,使用SIGIO信号通知应用程序进行IO操作
1.4 异步IO
由内核在数据拷贝完成时,通知应用程序(而信号驱动是告诉应用程序何时可以开始拷贝数据)
1.5 IO多路转接
虽然从流程图上看起来和阻塞IO类似. 实际上最核心在于IO多路转接能够同时等待多个文件
描述符的就绪状态
二、同步通信与异步通信
同步与异步关注的是消息通信机制
- 所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回,就得到返回值;换句话说,就是由调用者主动等待这个调用的结果;拷贝需要用户参与
- 异步则是相反,调用在发出之后,这个调用就直接返回了,所有没有返回结果;换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果;而是在调用发出后,被调用者通过状态、通知来通知调用者,或者通过回调函数处理这个调用。拷贝不需要用户参与,操作系统拷贝
这里的同步通信和进程之间的同步是完全不相干的概念
三、非阻塞IO
非阻塞IO可以open打开时设置flag
为非阻塞,这里主要介绍打开后的fd如何设置为非阻塞
3.1 fcntl
一个文件描述符,默认都是阻塞IO,fcntl函数用于已经打开的fd
该函数是一个系统调用函数
man 2 fcntl
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
fcntl
函数有5种功能:
- 复制一个现有的描述符 ---- cmd=F_DUPFD
- 获得/设置文件描述符标记–cmd=F_GETFD或F_SETFD
- 获得/设置文件状态标记-----cmd=F_GETFL或F_SETFL
- 获得/设置异步IO所有权-----cmd=F_GETOWN或F_SETOWN
- 获得/设置记录锁--------------cmd=F_GETLK,F_SETLK或F_SETLKW
传入的cmd的值不同,后面追加的参数也不相同
目前只使用第三种功能,获取/设置文件状态标记,就可以将一个文件描述符设置为非阻塞
3.2 实现函数SetNoBlock
基于fcntl
,实现一个SetNoBlock函数,将文件描述符设置为非阻塞
void SetNoBlock(int fd){
int fl = fcntl(fd,F_GETFL); //获取fd的状态标记
if(fl < 0){
perror("fcntl");
return ;
}
fcntl(fd, F_SETFL, fl | O_NONBLOCK); //将fl状态标记设置为非阻塞
}
3.3 如何使用函数SetNoBlock
以轮询的方式读取标准输入
#include<iostream>
#include<unistd.h>
#include<fcntl.h>
bool SetNonBlock(int fd){
int fl = fcntl(fd,F_GETFL);
if(fl < 0){
std::cerr << "fcntl error" << std::endl;
return false;
}
fcntl(fd,F_SETFL, fl | O_NONBLOCK);
return true;
}
int main()
{
#define NUM 1024
SetNonBlock(0);
while(true){
char buffer[NUM];
ssize_t size = read(0,buffer,sizeof(buffer)-1);
if(size < 0){
//不一定是出错了,有可能是底层没有数据
if(errno == EAGAIN || errno == EWOULDBLOCK ){
std::cout << "底层的数据没有就绪,你在轮询检测一下,try again " << std::endl;
continue;
}
if(errno == EINTR){
std::cout << "底层数据就绪未知,被信号中断 " << std::endl;
continue;
}
else{
std::cerr << "read error: " << size << " errno: "<< errno << std::endl;
break;
}
}
buffer[size] = 0; //主动给字符串最后添加'\0'
std::cout << "#echo: " <<buffer << std::endl;
}
return 0;
}
如果以非阻塞读取数据时,如果数据没有就绪,read是以出错的形式返回
如何判断是read真的出错?or 底层数据没有就绪 or read被信号中断
- errno == EAGAIN || errno == EWOULDBLOCK 时,说明数据没有就绪
- errno == EINTR ,说明被信号中断
grep -ER 'EAGAIN | EWOULDBLOCK' /usr/include/ 查看宏定义
边栏推荐
- STM8S105K4T6------串口发送和接收
- Zabbix设置邮件告警+企业微信告警
- FPGA解析B码----连载3
- 验证码业务逻辑漏洞
- 编写 BOLL 心得体会
- Rongyun "Audio and Video Architecture Practice" technical session [complete PPT included]
- SQL注入中 #、 --+、 --%20、 %23是什么意思?
- In the season of going overseas, the localization of Internet tips for going overseas
- unsafe.Pointer, pointer, reference in golang
- Exclude_reserved_words 排除关键字
猜你喜欢
Homemade bluetooth mobile app to control stm8/stm32/C51 onboard LED
说说数据治理中常见的20个问题
2022年茶艺师(中级)考试试题模拟考试平台操作
Why use Selenium for automated testing
云开发旅游打卡广场微信小程序源码(含视频教程)
自制蓝牙手机app控制stm8/stm32/C51板载LED
2022焊工(初级)上岗证题目模拟考试平台操作
4路双向HDMI综合业务高清视频光端机8路HDMI高清视频光端机
KingbaseES数据库启动失败,报“内存段超过可用内存”
Zabbix set up email alert + enterprise WeChat alert
随机推荐
2022年茶艺师(中级)考试试题模拟考试平台操作
How to read the resources files in the directory path?
安装postgis时报找不到“POSTGIS_VERSION”这个函数
【观察】超聚变:首提“算网九阶”评估模型,共建开放繁荣的算力网络
查看mysql死锁语法
【原创】启动Win10自带的XPS/OXPS阅读器
sqoop ETL tool
There are too many systems, how to realize multi-account interworking?
哎,又跟HR在小群吵了一架!
Asynchronous programming solution Generator generator function, iterator iterator, async/await, Promise
各位大佬好,麻烦问一下flink cdc oracle写入doris的时候,发现cpu异常,一下下跑
LeetCode每日一题(2285. Maximum Total Importance of Roads)
new Date converts strings into date formats Compatible with IE, how ie8 converts strings into date formats through new Date, how to replace strings in js, and explain the replace() method in detail
How to drop all tables under database in MySQL
怎样提高网络数据安全性
多线程间的通信方式你知道几种?
脚手架内容详解分析
董明珠直播时冷脸离场,员工频犯低级错误,自家产品没人能弄明白
Exclude_reserved_words 排除关键字
golang中的unsafe.Pointer,指针,引用