【高级IO-1】探索五种 I/O 模型及其高级I/O技术:基于 fcntl() 的代码应用

news2024/9/20 8:55:38

文章目录

  • 1. 五种IO模型
  • 2. 高级IO的重要概念
    • 2.1 同步通信 与 异步通信
    • 2.2 阻塞与非阻塞
    • 2.3 如何理解四者间的关系?
  • 3. 其他高级IO
      • 3.1 非阻塞 I/O
      • 3.2 纪录锁(Record Lock)
      • 3.3 系统 V 流机制
      • 3.4 I/O 多路复用(I/O Multiplexing)
      • 3.5 readv 和 writev 函数
      • 3.6 存储映射 I/O(mmap)
  • 4. 代码理解
    • 非阻塞IO
      • fcntl()
      • ① SetNonBlock(设置进程非阻塞状态)
      • ② **轮询方式读取标准输入**

1. 五种IO模型

我们以一个例子:对于钓鱼,可以总体分为等待和鱼上钩两个过程。

假设有五个人去钓场钓鱼:

  • A:一直盯着鱼钩,期间不做其他事,直到上鱼。
  • B:拿着手机,同时钓鱼和看手机,每隔一段时间去看一看鱼钩。
  • C:在鱼漂处挂一个铃铛,专注看手机,直要铃铛一响,就证明上鱼了,此时收杆。
  • D:直接架起10个鱼钩,来回走动,观察每个杆的情况。
  • E:根本不去钓场,让自己的小弟e去钓鱼,E安排好情况后就去上班了,当e钓到鱼后给E汇报情况即可。

不妨想想,哪个人的钓鱼效率最高?

正如前面的效率问题,只要单位时间等待的时间比重越短,效率最高,
比如钓场的一条鱼一定会上钩,那么对于D来说,钓到鱼的概率就是10/14,而其他人就是1/14,自然D的效率最高,而对于上面五种方式,实际上为五种IO模型:

  1. 阻塞式 IO (Blocking IO)

    • 当应用程序发起一个 IO 请求时,程序会被阻塞直到该 IO 操作完成。
    • 在阻塞式 IO 模型中,应用程序在等待 IO 操作完成期间会被挂起,直到数据准备好被读取或写入。
  2. 非阻塞式 IO (Non-blocking IO)

    • 在非阻塞式 IO 模型中,应用程序发起一个 IO 请求后不会被阻塞,而是立即返回。
    • 应用程序可以周期性地检查 IO 操作是否完成,从而避免了被阻塞的情况。
    • 虽然非阻塞 IO 模型减少了等待时间,但是需要应用程序不断轮询以检查 IO 状态,可能会增加 CPU 开销。
  3. 多路复用式 IO (I/O Multiplexing)

    • 多路复用式 IO 模型通过 selectpollepoll 等机制,允许应用程序同时监视多个 IO 事件。
    • 应用程序通过调用这些机制中的一个来等待多个 IO 事件的发生,从而避免了阻塞。
    • 当某个 IO 事件发生时,应用程序会被唤醒,并可以处理该 IO 事件。
  4. 信号驱动式 IO (Signal-driven IO)

    • 在信号驱动式 IO 模型中,应用程序发起一个 IO 请求后,继续执行其他任务。
    • 当 IO 操作完成时,操作系统向应用程序发送一个信号来通知 IO 完成,然后应用程序处理该信号并读取或写入数据。
  5. 异步 IO (Asynchronous IO)

    • 异步 IO 模型中,应用程序发起一个 IO 请求后,不需要等待 IO 操作完成,而是可以继续执行其他任务。
    • 当 IO 操作完成时,操作系统会通知应用程序,应用程序可以处理已完成的 IO 操作。

我们把IO分为了两个阶段(等 &拷贝),如果两个阶段参加了任意一个(或都参加),就叫做同步IO(A~D),如果没有参加任意一个阶段,则为异步IO(E)


2. 高级IO的重要概念

2.1 同步通信 与 异步通信

上面我们通过例子简单介绍了同步通信与异步通信的概念,这里我们加深一下了解:

  1. 同步通信

    • 在同步通信中,发送方发送数据后会等待接收方对数据的响应,直到接收到响应后才继续执行后续操作
    • 这意味着发送方和接收方在通信过程中是相互等待的,直到完成数据的传输和处理。
    • 同步通信的一个常见例子是阻塞式 I/O,比如传统的文件 I/O 操作和网络套接字的阻塞模式。
  2. 异步通信

    • 在异步通信中,发送方发送数据后不会立即等待接收方的响应,而是继续执行其他操作。
    • 发送方在发送数据后不会阻塞等待,而是通过回调函数、轮询或事件驱动等方式在后续得到接收方的响应或通知。
    • 异步通信的一个常见例子是非阻塞式 I/O,比如异步 I/O 操作和事件驱动的网络编程模型。

简单总结,即:

  • 在同步通信中,调用者发出请求后会主动等待结果的返回,直到得到结果才继续执行后续操作。
  • 在异步通信中,调用者发出请求后不会立即等待结果,而是继续执行其他操作,被调用者则通过状态、通知或回调函数等方式通知调用者结果的情况。

2.2 阻塞与非阻塞

阻塞:

  • 阻塞模式下,当程序执行一个操作时,如果该操作无法立即完成,程序将暂停执行,直到操作完成才会继续执行后续操作
  • 阻塞模式下,调用者会一直等待直到操作完成,期间无法进行其他任务。

非阻塞:

  • 非阻塞模式下,当程序执行一个操作时,如果该操作无法立即完成,程序将不会暂停执行,而是立即返回一个状态或错误码给调用者
  • 非阻塞模式下,调用者可以继续执行其他任务,不必等待操作完成。

2.3 如何理解四者间的关系?

  1. 同步通信可以是阻塞或非阻塞,例如:
    • 在同步阻塞通信中,发送方发送消息后会阻塞等待接收方响应;
    • 而在同步非阻塞通信中,发送方发送消息后可以继续执行其他任务,但会定期检查接收方的响应状态。

2. 异步通信通常是非阻塞的,因为发送方发送消息后不会等待接收方响应,而是继续执行其他任务,接收方处理完消息后再通知发送方。

3. 其他高级IO

下面简单介绍一些高级IO,下文将讨论的是I/O多路转接:

当然,下面是对这些高级 I/O 技术的简单介绍:

3.1 非阻塞 I/O

  • 定义:非阻塞 I/O 是一种 I/O 操作模式,在该模式下,I/O 操作不会阻塞当前线程。如果数据无法立即读取或写入,I/O 操作会立即返回,而不是让线程等待直到操作完成。
  • 特点
    • 适用于需要处理大量并发连接的场景。
    • 常用于网络编程中,例如在网络服务器中处理多个客户端连接。

3.2 纪录锁(Record Lock)

  • 定义:纪录锁是一种锁机制,用于对文件中的特定区域进行锁定。这种锁通常用于数据库系统或其他需要锁定特定记录的应用程序。
  • 特点
    • 可以锁定文件的部分内容而不是整个文件。
    • 提供精细的锁定控制,有助于避免锁争用和提高并发性能。

3.3 系统 V 流机制

  • 定义:系统 V 流(Streams)机制是一种用于处理数据流的 I/O 模型,支持对数据流的过滤和转换。通过使用流,可以将数据通过多个处理模块进行处理,每个模块可以独立处理数据的某一部分。
  • 特点
    • 提供了一种模块化的数据处理方式。
    • 常用于 Unix 系统中的管道和套接字编程中。

3.4 I/O 多路复用(I/O Multiplexing)

  • 定义:I/O 多路复用是指在单一线程中同时处理多个 I/O 流。它允许一个线程同时监控多个 I/O 通道(例如套接字),并在某些通道准备好进行读写操作时得到通知。
  • 实现方式
    • select:监控多个文件描述符,检查哪些描述符已准备好进行读写。
    • poll:类似于 select,但可以处理更多的文件描述符。
    • epoll(Linux):比 selectpoll 更高效,适用于处理大量并发连接的场景。
    • kqueue(BSD):与 epoll 类似,用于高效的事件通知。

3.5 readv 和 writev 函数

  • 定义
    • readv:从文件描述符中读取数据到多个缓冲区。
    • writev:从多个缓冲区写入数据到文件描述符。
  • 特点
    • 提高了 I/O 操作的效率,特别是对于需要处理多个缓冲区的数据时。
    • 允许在单一系统调用中处理多个缓冲区,减少了系统调用的开销。

3.6 存储映射 I/O(mmap)

  • 定义mmap 是一种将文件内容映射到进程的虚拟内存地址空间的技术。通过 mmap,可以将文件或设备映射到内存中,然后通过内存访问文件内容,而不是通过传统的读写操作。
  • 特点
    • 提高了文件 I/O 的效率,因为可以像访问内存一样访问文件内容。
    • 支持大文件的高效处理,并且可以用于实现进程间通信(IPC)。

4. 代码理解

非阻塞IO

fcntl()

fcntl用于对文件描述符进行各种操作,包括复制、关闭、获取/设置文件描述符标志以及对文件描述符的各种属性进行操作。

一般我们用fcntl有以下操作:

  • 复制描述符:可以通过 F_DUPFD 操作复制文件描述符。
  • 获取/设置文件描述符标志:可以通过 F_GETFLF_SETFL 操作来获取和设置文件描述符的状态标志,如非阻塞标志等。
  • 获取/设置文件状态标志:可以通过 F_GETFDF_SETFD 操作来 获取和设置
  • 获得/设置异步I/O所有权:通过F_GETOWN或F_SETOWN
  • 取消记录锁:可以通过 F_SETLK 操作取消记录锁。
  • 锁定文件:可以通过 F_SETLK 和 F_SETLKW 操作来对文件进行加锁,用于多进程/线程间对文件的访问控制。

下面我们利用fcntl写一个简单的代码例子(利用第三条:获取/设置文件状态标志):


① SetNonBlock(设置进程非阻塞状态)

基于上面介绍的fcntl,我们来实现一个设置进程非阻塞的代码:

bool SetNonBlock(int fd)
{
    int fl = fcntl(fd, F_GETFL); // 获取指定文件描述符 fd 的文件状态标志
    if(fl < 0) {
        return false;
    }
    fcntl(fd, F_SETFL, fl | O_NONBLOCK); // 设置文件状态标志为非阻塞

    return true;
}

对代码进行解释:

  1. int fl = fcntl(fd, F_GETFL)
    • 用于获取指定文件描述符 fd 的文件状态标志
    • F_GETFL 参数表示获取文件的状态标志;
  2. fcntl(fd, F_SETFL, fl | O_NONBLOCK)
    • 传入F_SETFL 参数,表示设置文件的状态标志
    • 通过将原来的文件状态标志 fl 与 O_NONBLOCK进行按位或 。O_NONBLOCK 是一个宏定义,用于表示将文件设置为非阻塞模式。

轮询方式读取标准输入

首先将标准输入设置为非阻塞,随后在循环内进行读取操作:

int main()
{
	SetNonBlock(0); // 将标准输入设置为非阻塞
    char buffer[1024];
	
	// 循环读取:
	// 在读取数据时,如果返回的字节数 s 大于0,表示成功读取了数据。然后将读取的数据输出到标准输出,并清空缓冲区。
	// 如果读取数据失败,则根据 errno 的值进行不同的处理。
    while(true)
    {
        sleep(1);
        errno = 0;
        // 非阻塞时,以出错形式返回,告知上层:数据未就绪
        ssize_t s = read(0, buffer, sizeof(buffer) - 1); // 0: 标准输入
        if(s > 0) {
            buffer[s-1] = 0;
            std::cout << "echo# " << buffer << " errno[---]" << errno << "errstring: " << strerror(errno) << std::endl;
        } else {
            // 若errno为11,意味着是底层数据未就绪,并非出错
            std::cout << "read \"error\" " << "errno: " << errno << "errstring: " << strerror(errno) << std::endl;
   		}
    }
}

执行上面的代码,会发现错误码为11:意味着数据非就绪(非阻塞下),并非一种错误,只需要等待数据就绪。

在这里插入图片描述
随后可以完善代码:

int main()
{
	SetNonBlock(0); // 设置一次非阻塞
    char buffer[1024];
    while(true)
    {
        sleep(2);
        errno = 0;
        // 非阻塞时,以出错形式返回,告知上层:数据未就绪
        ssize_t s = read(0, buffer, sizeof(buffer) - 1); // 0: 标准输入
        if(s > 0) {
            buffer[s-1] = 0;
            std::cout << "echo# " << buffer << " errno[---]" << errno << " | errstring: " << strerror(errno) << std::endl;
        } else {
            // 若errno为11,意味着是底层数据未就绪,并非出错
            // std::cout << "read \"error\" " << "errno:" << errno << " | errstring: " << strerror(errno) << std::endl;
            if(errno == EWOULDBLOCK || errno == EAGAIN) // 均为11
            {
                std::cout << "当前0号fd数据未就绪. try again!" << std::endl;
                continue;
            } 
            else if (errno == EINTR)
            {
                std::cout << "read被信号中断" << std::endl;
                continue;
            }
            else
            {
                // 错误处理
                std::cout << "read error" << std::endl;
            }
        }
    }
}

此时我们执行程序,当未输入数据时,进入的分支是errno == EWOULDBLOCK || errno == EAGAIN,一旦输入数据,可以正确读取

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2059312.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

自养号测评技术:如何挑选适合的IP环境方案

市面上的IP服务及常见问题 当前市场上常见的IP服务包括911、Luminati、Google Fi、TM流量卡、Socks专线等。这些服务在为用户提供网络代理或VPN服务时&#xff0c;常会遇到以下主要问题&#xff1a; 1. 高负载与重复率高&#xff1a;由于使用人数众多&#xff0c;导致网络拥堵…

投入式水位计的测量精度和稳定性如何保证

投入式水位计作为水位监测的重要工具&#xff0c;其测量精度和稳定性直接关系到数据的准确性和可靠性。在实际应用中&#xff0c;多种因素会影响投入式水位计的测量精度和稳定性&#xff0c;了解这些因素并采取相应的措施&#xff0c;是确保测量准确性的关键。 1、环境因素 温度…

Tomca安装和配置教程

目录 一.背景: 二.下载和安装Tomcat&#xff1a; 三.配置Tomcat环境变量 四.检查Tomcat安装成功 一.背景: Tocamt是Apache软件基金会(Apache Software Fouondation)的jakarta项目中的一个核心项目&#xff0c;由Apache、Sun以及其他一些公司及个人共同开发而成。Tocmat是一…

微服务⽹关

微服务网关&#xff08;API Gateway&#xff09;是微服务架构中的一个重要组成部分&#xff0c;它充当客户端与后端服务之间的单一入口。API网关负责处理所有的出入请求&#xff0c;提供集中式的安全、路由、负载均衡、监控等功能。 主要功能&#xff1a; 请求路由&#xff1a…

【JAVA】阿里巴巴 EasyExcel:高效的Excel处理解决方案

文章目录 EasyExcel1. EasyExcel 简介1.1 主要特点1.2 依赖配置 2. EasyExcel 核心功能2.1 写入 Excel 文件2.2 读取 Excel 文件 3. 业务开发示例3.1 用户数据导出3.2 用户数据导入 4. 进阶用法4.1 自定义转换器4.2 自定义格式 更多相关内容可查看 附官网地址&#xff1a;https…

Directory Opus 添加管理员获得所有权右键菜单

Directory Opus 添加管理员获得所有权右键菜单 在windows的资源管理器中添加管理员获得所有权的右键菜单很容易,通过注册表就可以了. 但是在Directory Opus需要另外的操作方式, 点击设置->文件类型: 选择运行DOpus函数,因为我的资源管理器已经有这个右键了,就选这个: …

营运管理系统应用架构设计

集中营运系统2020年1月《银行业集中营运规范(JR/T0173-2020号)》标准由全国金融标准化技术委员会审查通过,并由中国人民银行作为银发〔2020〕10号文件正式发布。集中运营的建设核心应该围绕多元化作业和运营能力共享两大方面服务。集中营运的系统建设方向如图10-01所示。 图…

ARP协议分析

目录 实验设备和环境 实验记录 1、ARP报文分析 &#xff08;1&#xff09;建立实验拓扑 &#xff08;2&#xff09;设置抓包接口 &#xff08;3&#xff09;启动设备&#xff0c;开始抓包 &#xff08;4&#xff09;协议分析 ARP代理 &#xff08;1&#xff09;建立实…

如何科学设定短信群发频率

在利用短信群发作为营销策略时&#xff0c;平衡好发送频率至关重要。过于频繁的短信可能招致客户反感甚至被屏蔽&#xff0c;而发送不足则可能导致品牌信息被遗忘。因此&#xff0c;精准把握短信群发频率&#xff0c;是提升客户体验与品牌记忆度的关键。以下是几个常见行业短信…

YOLOv5改进 | 模块融合 | C3融合可变形自注意力模块【模块缝合】

秋招面试专栏推荐 &#xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 &#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 专栏目录&#xff1a; 《YOLOv5入门 改…

豆瓣评分8.7!Python pandas创始人亲码的数据分析入门手册!

在众多解释型语言中&#xff0c;Python最大的特点是拥有一个巨大而活跃的科学计算社区。进入21世纪以来&#xff0c;在行业应用和学术研究中采用python进行科学计算的势头越来越猛。 近年来&#xff0c;由于Python有不断改良的库(主要是pandas)&#xff0c;使其成为数据处理任…

原神单机版【无脑一键搭建】纯单机*非私服*稳定版*

版本介绍 版本3.7、4.0、4.0、4.4、4.5、4.6稳定版【过分追新并不稳&#xff0c;合理才完美】 独家原神&#xff0c;游戏内自带剧情任务&#xff0c;完美仿官&#xff0c;一比一完美复制&#xff01; 已经拥有完美剧情、任务、副本、卡池、深渊、全物品、和全部功能和皮肤。 …

【漏洞复现】微商城系统 goods SQL注入漏洞

声明&#xff1a;本文档或演示材料仅用于教育和教学目的。如果任何个人或组织利用本文档中的信息进行非法活动&#xff0c;将与本文档的作者或发布者无关。 一、漏洞描述 微商城是基于微信这一广受欢迎的社交平台的商业应用&#xff0c;利用微信的广泛用户基础和快速传播特性&…

安泰ATA-7015高压放大器在机器人测试中的应用研究

随着机器人技术的快速发展&#xff0c;机器人在各个领域的应用日益广泛。然而&#xff0c;要确保机器人能够稳定、准确地完成各种任务&#xff0c;就需要对其进行严格的测试和评估。在机器人测试过程中&#xff0c;高压放大器作为一种关键的测试设备&#xff0c;发挥着不可替代…

dll文件丢失最简单的修复方法——电脑丢失dll文件一键修复

在日常使用Windows操作系统的过程中&#xff0c;DLL文件由于各种原因丢失或损坏是一个非常常见的问题。这可能导致软件运行不稳定或无法启动等问题&#xff0c;给用户带来诸多不便。尽管手动寻找并替换相应的DLL文件是一个可行的解决方案&#xff0c;但对于大多数用户而言&…

Linux修改密码出现 “passwd: Authentication token manipulation error”

文章目录 1. 问题现象2. 解决方法 1. 问题现象 修改密码出现&#xff1a; passwd: Authentication token manipulation error。 passwd root2. 解决方法 1.查看文件的扩展信息。 lsattr 命令用于显示文件的扩展属性&#xff0c;包括文件的特殊标志位。 /etc/passwd 是一个…

Java语言程序设计——篇十五(3)

&#x1f33f;&#x1f33f;&#x1f33f;跟随博主脚步&#xff0c;从这里开始→博主主页&#x1f33f;&#x1f33f;&#x1f33f; 欢迎大家&#xff1a;这里是我的学习笔记、总结知识的地方&#xff0c;喜欢的话请三连&#xff0c;有问题可以私信&#x1f333;&#x1f333;&…

设备巡检系统

在现代工业生产和各类设施管理中&#xff0c;设备的稳定运行至关重要。而凡尔码设备巡检系统的出现&#xff0c;为确保设备的可靠运转提供了强大的助力。 传统的纸质设备巡检容易作假、统计不及时、汇总困难、容易丢失、记录样式不丰富。而凡尔码设备巡检平台有着多种功能&…

考电工证,学历证丢了为什么能报名?

在面对学历证书遗失的情况下&#xff0c;许多人可能会感到焦虑和无助。幸运的是&#xff0c;如果你确认自己具有初中及以上学历&#xff0c;即使学历证书不慎丢失&#xff0c;仍有几种方法可以证明你的教育背景。以下是三种可行的替代方案&#xff1a; 户口本个人页拍照 首先&a…

PXE-Kickstart高效批量装机

文章目录 PXE高效批量网络装机安装顺序PXE批量装机部署优点基本部署过程 具体过程pxe---批量安装Kickstart---无人值守安装 实操pxe部分一、安装TFTP 服务二、修改TFTP服务的配置文件三、启用 TFTP服务四、安装DHCP服务五、修改DHCP服务的配置文件六、启用DHCP服务七、准备 Lin…