原子学习笔记1——阻塞和非阻塞IO

阻塞式 I/O 顾名思义就是对文件的 I/O 操作(读写操作)是阻塞式的,非阻塞式 I/O 同理就是对文件的I/O 操作是非阻塞的。
当对文件进行读操作时,如果数据未准备好、文件当前无数据可读,那么读操作可能会使调用者阻塞,直到有数据可读时才会被唤醒,这就是阻塞式 I/O 常见的一种表现;如果是非阻塞式 I/O,即使没有数据可读,也不会被阻塞、而是会立马返回错误。
普通文件的读写操作是不会阻塞的,不管读写多少个字节数据,read()或 write()一定会在有限的时间内返回,所以普通文件一定是以非阻塞的方式进行 I/O 操作,这是普通文件本质上决定的;但是对于某些文件类型,譬如管道文件、设备文件等,它们既可以使用阻塞式 I/O 操作,也可以使用非阻塞式 I/O进行操作。

1、阻塞IO读文件

在调用 open()函数打开文件时,为参数 flags 指定 O_NONBLOCK 标志,open()调用成功后,后续的 I/O 操作将以非阻塞式方式进行;这就是非阻塞 I/O 的打开方式,如果未指定 O_NONBLOCK 标志,则默认使用阻塞式 I/O 进行操作。
以读取鼠标为例,鼠标是一种输入设备,其对应的设备文件在/dev/input/目录下,如下所示:
在这里插入图片描述
使用 od 命令查看是哪个设备文件:

sudo od -x /dev/input/event3

移动鼠标或滚轮会打印出信息,如果没有试下其他的设备文件
在这里插入图片描述
下面以阻塞方式读取鼠标,调用 open()函数打开鼠标设备文件"/dev/input/event3",以只读方式打开,没有指定 O_NONBLOCK 标志,说明使用的是阻塞式 I/O;程序中只调用了一次 read()读取鼠标。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(void)
{char buf[100];int fd, ret;// /* 打开文件 fd = open("/dev/input/event3", O_RDONLY);if (-1 == fd) {perror("open error");exit(-1);}// /* 读文件 memset(buf, 0, sizeof(buf));ret = read(fd, buf, sizeof(buf));if (0 > ret) {perror("read error");close(fd);exit(-1);}printf("成功读取<%d>个字节数据\n", ret);// /* 关闭文件 close(fd);exit(0);
}

可以看出在不动滚轮的情况下阻塞
在这里插入图片描述
当移动滚轮是输出
在这里插入图片描述

2、非阻塞IO读文件

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(void)
{char buf[100];int fd, ret;// /* 打开文件 fd = open("/dev/input/event3", O_RDONLY | O_NONBLOCK);if (-1 == fd) {perror("open error");exit(-1);}// /* 读文件 memset(buf, 0, sizeof(buf));ret = read(fd, buf, sizeof(buf));if (0 > ret) {perror("read error");close(fd);exit(-1);}printf("成功读取<%d>个字节数据\n", ret);// /* 关闭文件 close(fd);exit(0);
}

可以看到非阻塞状态返回错误,因为在执行程序时并没有滑动滚轮,程序就退出了
在这里插入图片描述
可以对上述代码修改,使用轮训方式不断地去读取,直到鼠标有数据可读,read()将会成功
返回:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(void)
{char buf[100];int fd, ret;// /* 打开文件 fd = open("/dev/input/event3", O_RDONLY | O_NONBLOCK);if (-1 == fd) {perror("open error");exit(-1);}// /* 读文件 memset(buf, 0, sizeof(buf));for ( ; ; ) {ret = read(fd, buf, sizeof(buf));if (0 < ret) {printf("成功读取<%d>个字节数据\n", ret);close(fd);exit(0);}}
}

用top命令可以看出用轮训方式此进程CPU占用率非常高,将近100
在这里插入图片描述
阻塞式 I/O 的优点在于能够提升 CPU 的处理效率,当自身条件不满足时,进入阻塞状态,交出 CPU资源,将 CPU 资源让给别人使用;而非阻塞式则是抓紧利用 CPU 资源,譬如不断地去轮训,这样就会导致该程序占用了非常高的 CPU 使用率!

3、使用阻塞 I/O 实现并发读取

使用阻塞式方式同时读取鼠标和键盘,示例代码如下所示:
键盘是标准输入设备 stdin,进程会自动从父进程中继承标准输入、标准输出以及标准错误,标准输入设备对应的文件描述符为 0,所以在程序当中直接使用即可,不需要再调用 open 打开。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define MOUSE "/dev/input/event3"
int main(void)
{char buf[100];int fd, ret;// /* 打开鼠标设备文件 fd = open(MOUSE, O_RDONLY);if (-1 == fd) {perror("open error");exit(-1);}// /* 读鼠标 memset(buf, 0, sizeof(buf));ret = read(fd, buf, sizeof(buf));printf("鼠标: 成功读取<%d>个字节数据\n", ret);// /* 读键盘 memset(buf, 0, sizeof(buf));ret = read(0, buf, sizeof(buf));printf("键盘: 成功读取<%d>个字节数据\n", ret);// /* 关闭文件 close(fd);exit(0);
}

在这里插入图片描述
可以看出阻塞IO无法实现同时读取,要先读鼠标再读键盘。用非阻塞就可以解决这个问题

4、使用非阻塞 I/O 实现并发读取

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define MOUSE "/dev/input/event3"
int main(void)
{char buf[100];int fd, ret, flag;// /* 打开鼠标设备文件 fd = open(MOUSE, O_RDONLY | O_NONBLOCK);if (-1 == fd) {perror("open error");exit(-1);}// /* 将键盘设置为非阻塞方式 flag = fcntl(0, F_GETFL); //先获取原来的 flagflag |= O_NONBLOCK; //将 O_NONBLOCK 标准添加到 flagfcntl(0, F_SETFL, flag); //重新设置 flagfor ( ; ; ) {// /* 读鼠标 ret = read(fd, buf, sizeof(buf));if (0 < ret)printf("鼠标: 成功读取<%d>个字节数据\n", ret);// /* 读键盘 ret = read(0, buf, sizeof(buf));if (0 < ret)printf("键盘: 成功读取<%d>个字节数据\n", ret);}// /* 关闭文件 close(fd);exit(0);
}

在这里插入图片描述
注意:因为标准输入文件描述符(键盘)是从其父进程进程而来,并不是在我们的程序中调用 open()打开得到的,使用fcntl()函数将标准输入设置为非阻塞 I/O。

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

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

相关文章

modbus TCP 应用

Modbus TCP 应用介绍 一、原理 Modbus TCP/IP 协议是工业通信系统领域的基石。它是一种与以太网结合使用的应用层消息传递协议&#xff0c;可实现不同类型网络上连接的设备之间的客户端/服务器通信。Modbus 最初是一种 Modbus 串行协议 (Modbus RTU)&#xff0c;现已发展到包…

Android画布Canvas绘图scale translate,Kotlin

Android画布Canvas绘图scale & translate&#xff0c;Kotlin <?xml version"1.0" encoding"utf-8"?> <androidx.appcompat.widget.LinearLayoutCompat xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app"…

VSCode如何编辑Markdown文件

VSCode如何编辑Markdown文件 一、安装插件二、常用命令 一、安装插件 需要在VSCode安装一个插件Markdown Theme Kit 二、常用命令 1、CtrlShiftV 预览模式

Swift爬虫采集唯品会商品详情

我有个朋友之前在唯品会开的店&#xff0c;现在想转战其他平台&#xff0c;想要店铺信息商品信息全部迁移过去&#xff0c;如果想要人工手动操作就有点麻烦了&#xff0c;然后有天找到我 &#xff0c;让我看看能不能通过技术手段实现商品信息迁移。嫌来无事&#xff0c;写了下面…

飞天使-docker知识点6-容器dockerfile各项名词解释

文章目录 docker的小技巧dockerfile容器为什么会出现启动了不暂停查看docker 网桥相关信息 docker 数据卷 docker的小技巧 [rootlight-test playbook-vars[]# docker inspect -f "{{.NetworkSettings.IPAddress}}" d3a9ae03ae5f 172.17.0.4docker d3a9ae03ae5f:/etc…

数据结构-07-二叉树

前面学习的栈、队列等等都是线性表结构。树是一种非线性表结构&#xff0c;比线性表的数据结构要复杂。 1-树tree “树”这种数据结构类似我们现实生活中的“树”&#xff0c;这里面每个元素我们叫作“节点”&#xff1b;用来连线相邻节点之间的关系&#xff0c;我们叫作“父子…

OxLint 发布了,Eslint 何去何从?

由于最近的rust在前端领域的崛起&#xff0c;基于rust的前端生态链遭到rust底层重构&#xff0c;最近又爆出OxLint&#xff0c;是一款基于Rust的linter工具Oxlint在国外前端圈引起热烈讨论&#xff0c;很多大佬给出了高度评价&#xff1b;你或许不知道OxLint&#xff0c;相比ES…

「X」Embedding in NLP|神经网络和语言模型 Embedding 向量入门

在「X」Embedding in NLP 进阶系列中&#xff0c;我们介绍了自然语言处理的基础知识——自然语言中的 Token、N-gram 和词袋语言模型。今天&#xff0c;我们将继续和大家一起“修炼”&#xff0c;深入探讨神经网络语言模型&#xff0c;特别是循环神经网络&#xff0c;并简要了解…

用友NC word.docx任意文件读取漏洞

文章目录 产品简介漏洞概述指纹识别漏洞利用修复建议 产品简介 用友NC是一款企业级ERP软件。作为一种信息化管理工具&#xff0c;用友NC提供了一系列业务管理模块&#xff0c;包括财务会计、采购管理、销售管理、物料管理、生产计划和人力资源管理等&#xff0c;帮助企业实现数…

STM32-TIM定时器编码器

目录 一、编码器接口简介 二、正交编码器 三、编码器框图 四、编码器接口基本结构 五、工作模式&#xff08;库函数第二个参数&#xff09; 六、实例 6.1 均不反相 6.2 TI1反相 七、开发步骤 八、编码器库函数 九、实验 一、编码器接口简介 >Encoder Interface 编…

npm ,yarn 更换使用国内镜像源,阿里源,清华大学源

在平时开发当中&#xff0c;我们经常会使用 Npm&#xff0c;yarn 来构建 web 项目。但是npm默认的源的服务器是在国外的&#xff0c;如果没有梯子的话。会感觉特别特别慢&#xff0c;所以&#xff0c;使用国内的源是非常有必要的。 在这里插入图片描述 Nnpm&#xff0c; yarn …

人工智能与量子计算:开启未知领域的智慧之旅

导言 人工智能与量子计算的结合是科技领域的一场创新盛宴&#xff0c;引领我们进入了探索未知领域的新时代。本文将深入研究人工智能与量子计算的交汇点&#xff0c;探讨其原理、应用以及对计算领域的深远影响。 量子计算的崛起为人工智能领域注入了新的活力&#xff0c;开启了…