【Linux】五种IO模型 + 非阻塞IO
【Linux】非阻塞IO
·
📝前言:
这篇文章我们来讲讲Linux五种IO模型 + 非阻塞IO:
- 五种IO模型
- 非阻塞IO
- fcntl
- 非阻塞轮询模版
🎬个人简介:努力学习ing
📋个人专栏:Linux
🎀CSDN主页 愚润求学
🌄其他专栏:C++学习笔记,C语言入门基础,python入门基础,C++刷题专栏
这里写目录标题
一,五种IO模型
IO = 等 + 拷贝
I/O 效率是 “减少等待” 和 “优化拷贝” 共同决定的。但在硬件相同,拷贝次数相同的场景下,减少等待时间是提高IO效率的关键。
-
阻塞IO:数据到来前,进程一直在
read
等,直到数据到来 -
非阻塞IO:如果内核还未将数据准备好, 系统调用仍然会直接返回, 并且返回EWOULDBLOCK 错误码
- 非阻塞 IO 往往需要程序员循环的方式反复尝试读写文件描述符, 这个过程称为轮询. 这对 CPU 来说是较大的浪费, 一般只有特定场景下才使用.
-
信号驱动 IO:内核将数据准备好的时候, 使用 SIGIO 信号通知应用程序进行 IO操作。(属于同步IO,因为拷贝是自己完成的)
-
IO 多路转接:同时等待多个文件描述符的就绪状态。
-
异步 IO:由内核在数据拷贝完成时, 通知应用程序(异步IO不参与 等 + 拷贝的任意一个过程)
同步 vs 异步:
- 同步IO:参与等 or 拷贝中任意一个阶段(调用方需要主动等待结果就绪,或要亲自处理结果)。同步通信:参与调用 or 等待返回结果任意一个阶段,调用返回,结果跟着返回。
- 异步:不参与任意一个阶段(调用方无需等待结果,由 “第三方”等待结果并处理,处理完后再通知调用方“完成了”)。
二,非阻塞IO
1. fcntl
一个文件描述符,默认都是阻塞 IO。fcntl
允许我们设置文件描述符的标记位,让我们可以把文件描述符设置成非阻塞IO
cmd
:命令,它决定了fcntl
函数要执行的操作类型。不同的cmd
对应不同的功能,也对应不同的返回值例如(主要用到的):F_GETFL
:获取文件的状态标志(比如是否为非阻塞模式等)。F_SETFL
:设置文件的状态标志。
... /* arg */
:可变参数,根据cmd
的不同,这个参数的意义和类型也不同。例如,当cmd
是F_SETFL
时,arg
用于传递要设置的标志。- 标记有:
O_APPEND
,O_NONBLOCK
…(本质是设置了特定比特位的宏) - 一般我们可以先通过
F_GETFL
获取到原来的标志(返回值是一个位图),然后再F_SETFL
上原来标志 | 新标志
- 标记有:
2. 非阻塞轮询模版
以轮询方式读取标准输入为例(标准输入0
,默认是非阻塞输入的)
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
void SetNoBlock(int fd)
{
int fl = fcntl(0, F_GETFL);
if(fl < 0)
{
perror("fcntl error");
return;
}
fcntl(0, F_SETFL, fl | O_NONBLOCK);
}
int main()
{
SetNoBlock(0); // 设置非阻塞
while(true)
{
char buffer[1024] = {0};
// 从键盘读取数据,不会阻塞读。
// 读不到就返回: <0 认为:"出错"。
// ==0是:写端已经关闭且无数据残留
ssize_t read_size = read(0, buffer, sizeof(buffer) - 1);
if(read_size < 0)
{
// 非阻塞无数据
// 这两种"错误"代表暂无数据,重试可能成功
// 两个错误码值相同,但是历史与系统的原因所以最好两个都判断
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
printf("数据暂未就绪...\n"); // 这才是无输入时的正确提示
sleep(1);
}
// 真正的错误
else
{
perror("read error"); // 其他错误(如文件描述符无效)
}
continue;
}
printf("input: %s", buffer);
}
return 0;
}
运行效果:
🌈我的分享也就到此结束啦🌈
要是我的分享也能对你的学习起到帮助,那简直是太酷啦!
若有不足,还请大家多多指正,我们一起学习交流!
📢公主,王子:点赞👍→收藏⭐→关注🔍
感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!
更多推荐
所有评论(0)