操作系统:高级IO

高级IO

1.关于IO

IO的基本类型:

I代表输入(Input):

  • 从外部设备或来源(如键盘、鼠标、文件、网络)读取数据到计算机中。
  • 示例:用户键入的文本、从文件读取的数据、从网络接收到的数据包。

O代表输出(Output):

  • 将计算机处理后的数据发送到外部设备或目的地(如显示器、打印机、文件、网络)。
  • 示例:屏幕上显示的文本、写入文件的数据、发送到网络的消息。

2.IO模型

①.阻塞IO

        在进行IO操作时,当前进程或者线程会被阻塞,直到IO操作完成。

  

        例如scanf,在你没有输入任何内容时,他会卡在那里,直到等到你输入内容回车后,菜继续执行。那么在没有输入任何内容时,进程就进入到了阻塞态,等待你输入内容,然后进入到就绪队列,然后被CPU调度变为运行态,最终执行完成。

②.非阻塞IO

  • 轮询:比如你又一个快递,你会去查看,但是查看之后你不会一直去等待这个快递在这个过程中什么事你都不去干。正常来说,你会看一下快递到了吗,然后就去干别的事,然后过一段时间又看一下到了吗,直到你的快递到达。这个过程就叫做轮询
  • 信号机制:等待一个信号的发生,然后做出对应的操作
  • 通信机制:计算机网络
  • 非阻塞IO适用于IO多路复用
③.缓存IO

  • 缓存:当你寄快递,快递公司不可能只为了
    #include <sys/select.h>int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
    一个快递发一个车,他会等到一定数量才发车。这就叫做缓存。
  • 行缓冲机制:C语言中的3个标准流
④.直接IO

  • 直接写入到硬盘,没有任何缓存。
⑤.同步IO

  • 当你通过IO进行写入时,他会写入到缓存,然后当你保存时写入到磁盘上,最后完全写入到磁盘后才进行返回,保存成功。

3.IO多路复用

为什么要引入IO多路复用?

为了是一个程序能够同时监听多个文件描述符(文件、套接字等)以等待事件(如数据到达、IO写入等等)。这样通过这样就可以更方便的去管理阻塞的问题。

IO多路复用相应函数:
select

函数原型:

#include <sys/select.h>int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
参数:
  • int nfds:需要监视的文件描述符数目,是所有文件描述符中最大值加1,例如现在我需要监听0,1,2,也就是我程序对应的三个标准流输入,输出,错误输出。那么nfds的值就应该为3
  • fd_set *readfds:监视是否可读的文件描述符集合
  • fd_set *writefds:监视是否可写的文件描述符集合
  • fd_set *exceptfds:监视是否有异常条件的文件描述符集合

        上面3个参数,都分别可以看为文件fd的集合,也就是每一个对应的就是一个fd池,可能对应的每一个fd池中会有多个fd的文件描述符。select会分别去监视每个对应的池。

        一些对于fd_set的宏操作:

  1. FD_ZERO(fd_set *set):将 fd_set 清空。
  2. FD_SET(int fd, fd_set *set):将文件描述符 fd 加入 fd_set
  3. FD_CLR(int fd, fd_set *set):从 fd_set 中移除文件描述符 fd
  4. FD_ISSET(int fd, fd_set *set):检查 fd 是否在 fd_set 中。

  • struct timeval *timeout:等待的超时时间。如果设置为NULL,那么select将一直阻塞,f直到有反馈。
struct timeval {long    tv_sec;         /* seconds 秒*/long    tv_usec;        /* microseconds 微秒*/
};
返回值

返回-1:表示发生错误,并设置“errno"

返回0:表示再指定的事件超时,并没有文件描述符就绪

返回正数:表示有一个或者多个文件描述符就绪

例子:
#include <stdio.h>
#include <sys/select.h>
#include <stdlib.h>
#include <unistd.h>int main() {fd_set refd;struct timeval timeout;int fd = 0;//标准输入流FD_ZERO(&refd);//初始化清空一下fd_setFD_SET(fd, &refd);//将标准输入流放入refd这个fd_set中//设置超时时间timeout.tv_sec = 5;timeout.tv_usec = 0;int ret = select(fd + 1, &refd, NULL, NULL, &timeout);//说明没有文件if (ret == 0)  {fprintf(stderr, "Timeout Nothing");exit(1);}//发生错误if (ret < 0) {perror("select error");exit(2);}//开始对标准输入流读取char buff[100] = {0};ssize_t byt_read =  read(fd, buff, sizeof(buff) - 1);if (byt_read < 0) {perror("read error");exit(1);}printf("sucessful read : ");printf("%s", buff);return 0;
}

演示结果:

优缺点

优点:简单易用,跨平台,适用于少量文件描述符,文件描述符上限为1024

缺点:再处理大量文件描述符时性能会下降。

poll

函数原型

#include <poll.h>int poll(struct pollfd *fds, nfds_t nfds, int timeout);
参数:
  • struct pollfd &fds:指向pollfd结构体数组的指针,这个结构体中包含了需要监听的文件描述符,以及监听事件和实际发生的事件。
  • nfds_t nfds:fds数组的大小
  • int timeout:等待的超时事件,为-1就一直阻塞等待,为0就立即返回;为正数那么就是毫秒数内阻塞
struct pollfd {int fd;         // 文件描述符short events;   // 监视的事件short revents;  // 实际发生的事件
};
  1. int fd:监听的文件描述符
  2. events:指定要监视的实际事件:
  • POLLIN:有数据可读。
  • POLLRDNORM:普通数据可读。
  • POLLRDBAND:优先数据可读。
  • POLLPRI:有紧急数据可读。
  • POLLOUT:可写数据。
  • POLLWRNORM:普通数据可写。
  • POLLWRBAND:优先数据可写。
  • POLLERR:发生错误。
  • POLLHUP:挂起。
  • POLLNVAL:无效请求。

     3.revents:由内核设置,指实际发生的事

返回值

正数:就绪文件数量

0:表示超时了没有任何文件就绪

-1:发生错误,设置errno

例子:
#include <stdio.h>
#include <poll.h>
#include <stdlib.h>
#include <unistd.h>int main(){struct pollfd fds[1];int fd = 0;//还是监听标准输入流fds[0].fd = fd;fds[0].events = POLLIN; //监视fds集合,集合中只有一个文件描述符,等但时间为5000msint ret = poll(fds, 1, 5000);//发生错误 if (ret == -1)  {perror("poll error");}if (ret == 0) {fprintf(stderr, "poll Nothing\n");exit(1);}//与上它为真说明发生的事件就是这个if (fds[0].revents & POLLIN)  {char buff[100] = {0};ssize_t byt_read = read(fd, buff, sizeof(buff) - 1);if (byt_read < 0) {perror("read error");exit(1);}printf("poll sucess : %s", buff);}return 0;
}

运行结果:

优缺点:

优点:

  • 对于select没有文件描述符数量的限制,适合处理大量文件描述符
  • 更灵活,提供了许多处理事件的接口,允许监视更过种类的事件

缺点:

  • 在处理大量文件描述符时,poll需要扫描整个文件描述符数组,那么性能就会下降
  • 对比select,poll的使用更复杂‘
epoll函数家族

epoll_createl:创建一个epoll

函数原型

#include <sys/epoll.h>int epoll_create1(int flags);
  • 参数

  • flags:创建标志,可以为 0EPOLL_CLOEXEC,后者在创建 epoll 文件描述符时设置 FD_CLOEXEC 标志。
  • 返回值

  • 成功时,返回 epoll 实例的文件描述符。
  • 失败时,返回 -1 并设置 errno

eooll_ctl:控制epoll实例上的事件

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
  • 参数

  • epfd:由 epoll_create1 返回的 epoll 实例文件描述符。
  • op:要执行的操作,可以是以下值之一:
    • EPOLL_CTL_ADD:添加事件。
    • EPOLL_CTL_MOD:修改事件。
    • EPOLL_CTL_DEL:删除事件。
  • fd:需要操作的目标文件描述符。
  • event:指向 epoll_event 结构体的指针,指定感兴趣的事件和关联的数据。

epoll_event

struct epoll_event {uint32_t events;    // 监视的事件epoll_data_t data;  // 用户数据
};
  • events:感兴趣的事件,可以是以下值的组合:
    • EPOLLIN:有数据可读。
    • EPOLLOUT:可写数据。
    • EPOLLRDHUP:对方关闭连接或半关闭连接。
    • EPOLLPRI:有紧急数据可读。
    • EPOLLERR:发生错误。
    • EPOLLHUP:挂起。
    • EPOLLET:边沿触发。
    • EPOLLONESHOT:一次性事件。
  • data:用户数据,可用于存储文件描述符或其他用户定义的数据。

epoll_data_t

typedef union epoll_data {void *ptr;int fd;uint32_t u32;uint64_t u64;
} epoll_data_t;

epoll_wait:等待事件的发生

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

参数

  • epfd:由 epoll_create1 返回的 epoll 实例文件描述符。
  • events:指向 epoll_event 结构体数组的指针,用于存储发生的事件。
  • maxevents:数组的大小,即一次最多返回的事件数。
  • timeout:等待的超时时间(以毫秒为单位)。如果为 -1,则无限期阻塞;如果为 0,则立即返回。

返回值

  • 返回正值:表示已就绪的文件描述符数量。
  • 返回 0:表示在指定的超时时间内没有文件描述符就绪。
  • 返回 -1:表示发生错误,并设置 errno
例子
#include <stdio.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>int main() {int epoll_fd = epoll_create1(0);if (epoll_fd < 0) {perror("epoll_create1 error");exit(1);}struct epoll_event event;event.events = EPOLLIN;//监听可读事件event.data.fd = 0;//文件描述符设置为0,标准输入if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, 0, &event) < 0)  {perror("epoll_ctl error");close(epoll_fd);exit(1);}struct epoll_event events[1];int ret = epoll_wait(epoll_fd, events, 1, 5000);if (ret < 0) {perror("epoll_wait error");exit(1);}if (ret == 0) {fprintf(stderr, "Timeout epoll_wait Nothing\n");exit(1);}if (events[0].events & EPOLLIN) {char buff[100] = {0};ssize_t b_read = read(0, buff, sizeof(buff) - 1);if (b_read < 0) {perror("b_read error");exit(1);}printf("epoll sucess : %s", buff);}close(epoll_fd);return 0;
}
优缺点:

        优点:

  • 高效,性能不会随着文件描述符增多而增多
  • 边沿触发:epoll支持边沿触发模式,可以减少系统调用次数,提高性能,也就是减少变态次数
  • 支持一次性事件:使用 EPOLLONESHOT 标志设置一次性事件,并在事件处理完毕后再次将文件描述符添加回 epoll 实例

        缺点

  • 只能再linux上使用,是linux特有的系统调用,无法跨平台
  • 对于poll和select调用更复杂

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

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

相关文章

git 版本回退-idea

1、选中项目&#xff0c;右键&#xff0c;打开 git历史提交记录 2、选中想要回退的版本&#xff0c;选择 hard&#xff08;不保留版本记录&#xff09; 3、最终选择强制提交&#xff08;必须强制&#xff09; OK&#xff0c;搞定

OpenCV 图像预处理—图像金字塔

文章目录 相关概念高斯金字塔拉普拉斯金字塔应用 构建高斯金字塔为什么要对当前层进行模糊&#xff1f;1. 平滑处理2. 减少混叠&#xff08;Aliasing&#xff09;3. 多尺度表示4. 图像降采样 举个栗子创建高斯金字塔和拉普拉斯金字塔&#xff0c;并用拉普拉斯金字塔恢复图像 相…

【PyTorch】基于YOLO的多目标检测项目(二)

【PyTorch】基于YOLO的多目标检测项目&#xff08;一&#xff09; 【PyTorch】基于YOLO的多目标检测项目&#xff08;二&#xff09; YOLO-v3网络由跨距为2的卷积层、跳跃连接层和上采样层组成&#xff0c;没有池化层。网络接收一幅416 * 416的图像作为输入&#xff0c;并提供三…

C++从入门到入土(三)--6个默认成员函数

目录 前言 什么是默认成员函数 构造函数 概念 特性 析构函数 概念 特性 拷贝构造函数 概念 特性 赋值运算符重载 特性 前言 很久没有更新文章了&#xff0c;最近把类和对象相关的知识重新回顾了一遍&#xff0c;打算从今天开始继续更新C从入门到入土系列。前面我们…

DVWA中SQL注入漏洞细说

SQL注入是一种安全漏洞&#xff0c;它允许攻击者通过影响Web应用程序的后端数据库。攻击者可以通过在输入字段中插入恶意SQL代码来执行非授权查询&#xff0c;从而获取或修改数据。 在开始启动SQL注入之前我们先将DVWA的安全等级调整到Low 1、我们在SQL Injection中输入 1 and…

Linux文件恢复

很麻烦 一般还是小心最好 特别恢复的时候 可能不能选择某个文件夹去扫描恢复 所以 删除的时候 用rm -i代替rm 一定小心 以及 探索下linux的垃圾箱机制 注意 一定要恢复到不同文件夹 省的出问题 法1 系统自带工具 debugfs 但是好像不能重启&#xff1f; testdisk 1、安装 …

Flink笔记整理(四)

Flink笔记整理&#xff08;四&#xff09; 文章目录 Flink笔记整理&#xff08;四&#xff09;六、Flink中的时间和窗口6.1 窗口&#xff08;Window&#xff09;窗口的概念窗口的分类窗口API概览窗口分配器窗口函数&#xff08;Window Functions&#xff09; 6.2 时间语义&…

MySQL的库操作和表操作

文章目录 MYSQLSQL语句分类服务器&#xff0c;数据库和表的关系 库操作表操作 MYSQL SQL语句分类 DDL【data definition language】 数据定义语言&#xff0c;用来维护存储数据的结构代表指令: create, drop, alterDML【data manipulation language】 数据操纵语言&#xff0…

关键路径算法(Critical Path)

这个算法《算法导论》中并没有提及&#xff0c;很多书和博客说的有点奇怪&#xff0c;所以写本文作为笔记。 关键路径是什么 关键路径的定义非常简单&#xff1a;就是一个图中&#xff0c;权值之和最大的路径就是关键路径。 那么就可以知道关键路径不唯一。 为什么有关键路…

安装 moleculeSTM 踩坑日记

“学习 LLM &#xff0c;在大模型时代为自己存张船票”。 相信很多人都有这样的想法。那么&#xff0c;在 AI for science 领域&#xff0c;哪些 LLM 模型值得一试呢&#xff1f; 笔者认为&#xff1a; LLM 直接预测 SMILES 性质 or 直接生成 SMILES 的技术路线是行不通的。因…

搭建DNS正向解析,反向解析+搭建DNS主从架构+搭建DNS多区域+时间同步

主要在局域网中配置&#xff0c;不存在外网 正向解析&#xff1a;域名解析为IP named.conf 解决权限 named.rfc1912.zones 解决解析方式 环境准备&#xff1a;三台机器都做下面的操作 基础配置&#xff1a;网络配置&#xff0c;关闭安全架构&#xff0c;关闭防火墙&#x…

使用langchain4j调用大模型写个聊天助手

LangChain4j是一款基于Java的高效、灵活的AI大模型应用框架&#xff0c;专为简化Java应用程序与LLMs&#xff08;大语言模型&#xff09;的集成而设计。它提供统一API和模块化设计&#xff0c;支持多种LLM提供商和嵌入模型&#xff0c;以及丰富的工具箱&#xff0c;如AI服务和R…

光伏混合储能直流微网直流母线电压下垂控制MATLAB仿真

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 模型简介 此模型以混合储能系统为研究对象&#xff0c;采用基于关联参数SOC的改进下垂控制策略&#xff0c;将初始下垂系数与储能单元SOC的n次幂的比值作为现行下垂系数&#xff0c;通过改变n值&#xff0c;…

【快速上手ESP32(ESP-IDF)】ADC数模转换(含单次转换和连续转换以及校准)

这篇为重置版。 因为准备录制视频了&#xff0c;然后回过头看看之前讲ADC的文章发现有不少错误的地方&#xff08;但是代码是可以用的&#xff09;&#xff0c;而且讲的也不全面&#xff0c;因此决定写下这个重置版。 这边提供三种使用ADC的方法&#xff0c;第一种是老方法&a…

港科夜闻 | 香港科大与阿里巴巴合作,计划成立大数据与人工智能联合实验室

关注并星标 每周阅读港科夜闻 建立新视野 开启新思维 1、香港科大与阿里巴巴合作&#xff0c;计划成立大数据与人工智能联合实验室。香港科大7月19日与阿里巴巴集团签署合作备忘录&#xff0c;计划成立「香港科技大学–阿里巴巴大数据与人工智能联合实验室」&#xff0c;就生成…

科普文:万字梳理31个Kafka问题

1、 kafka 是什么,有什么作用 2、Kafka为什么这么快 3、Kafka架构及名词解释 4、Kafka中的AR、ISR、OSR代表什么 5、HW、LEO代表什么 6、ISR收缩性 7、kafka follower如何与leader同步数据 8、Zookeeper 在 Kafka 中的作用&#xff08;早期&#xff09; 9、Kafka如何快…

UDP程序设计

UDP协议概述 UDP&#xff0c;User Datagram Protocol&#xff0c;用户数据报协议&#xff0c;是一个简单的面向数据报(package-oriented)的传输层协议&#xff0c;规范为&#xff1a;RFC 768。 UDP提供数据的不可靠传递&#xff0c;它一旦把应用程序发给网络层的数据发送出去…

Java | Leetcode Java题解之第300题最长递增子序列

题目&#xff1a; 题解&#xff1a; class Solution {public int lengthOfLIS(int[] nums) {int len 1, n nums.length;if (n 0) {return 0;}int[] d new int[n 1];d[len] nums[0];for (int i 1; i < n; i) {if (nums[i] > d[len]) {d[len] nums[i];} else {int…

做一个能和你互动玩耍的智能机器人之四--固件

在openbot的firmware目录下我们能够找到arduino的固件源码和相关的文档。 openbot的controller目录下&#xff0c;是控制器的代码目录&#xff0c;用来控制机器人做一些动作。未来的目标是加入大模型&#xff0c;使其能够理解人的语言和动作来控制。 固件代码&#xff0c;支持…