【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;

}

🌈我的分享也就到此结束啦🌈
————————————————
版权声明:本文为CSDN博主「愚润泽」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/tan_run/article/details/151683739

阅读剩余
THE END