【Linux】五种IO模型 + 非阻塞IO
📝前言:
这篇文章我们来讲讲Linux五种IO模型 + 非阻塞IO:
- 五种IO模型
- 非阻塞IO
- fcntl
- 非阻塞轮询模版
🎬个人简介:努力学习ing
📋个人专栏:Linux
🎀CSDN主页 愚润求学
🌄其他专栏:C++学习笔记,C语言入门基础,python入门基础,C++刷题专栏
这里写目录标题
- 一,五种IO模型
- 二,非阻塞IO
- 1. fcntl
- 2. 非阻塞轮询模版
一,五种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;}
运行效果:

🌈我的分享也就到此结束啦🌈
要是我的分享也能对你的学习起到帮助,那简直是太酷啦!
若有不足,还请大家多多指正,我们一起学习交流!
📢公主,王子:点赞👍→收藏⭐→关注🔍
感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!
