【Linux】管道的读写特点和管道设置为非阻塞

news2024/12/26 0:56:10

目录

  • 管道的读写特点
  • 管道设置为非阻塞

橙色

管道的读写特点

使用管道时,需要注意以下几种特殊的情况(假设都是阻塞I/O操作)

  1. 所有的指向管道写端的文件描述符都关闭了(管道写端引用计数为0),有进程从管道的读端读数据,那么管道中剩余的数据被读取以后,再次read会返回0,就像读到文件末尾一样。

  2. 如果有指向管道写端的文件描述符没有关闭(管道的写端引用计数大于0),而持有管道写端的进程也没有往管道中写数据,这个时候有进程从管道中读取数据,那么管道中剩余的数据被读取后,再次read会阻塞,直到管道中有数据可以读了才读取数据并返回。

  3. 如果所有指向管道读端的文件描述符都关闭了(管道的读端引用计数为0),这个时候有进程向管道中写数据,那么该进程会收到一个信号SIGPIPE, 通常会导致进程异常终止。

  4. 如果有指向管道读端的文件描述符没有关闭(管道的读端引用计数大于0),而持有管道读端的进程也没有从管道中读数据,这时有进程向管道中写数据,那么在管道被写满的时候再次write会阻塞,直到管道中有空位置才能再次写入数据并返回。

总结:
    读管道:

        管道中有数据,read返回实际读到的字节数。
        管道中无数据:
            写端被全部关闭,read返回0(相当于读到文件的末尾)
            写端没有完全关闭,read阻塞等待

    写管道:

        管道读端全部被关闭,进程异常终止(进程收到SIGPIPE信号)
        管道读端没有全部关闭:
            管道已满,write阻塞
            管道没有满,write将数据写入,并返回实际写入的字节数

管道设置为非阻塞

在正常的管道读写中,如果一方没有写入,管道内又没有数据了,那么就会阻塞。如下面的代码,父进程读取,子进程写入。每写入一次,子进程就会睡眠10秒。那么父进程在读取了一次(也就是读取完)管道内的内容后,就会阻塞10s,等待下一次子进程写入。期间程序会停止。

#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

int main() {

    // 在fork之前创建管道
    int pipefd[2];
    int ret = pipe(pipefd);
    if(ret == -1) {
        perror("pipe");
        exit(0);
    }

    // 创建子进程
    pid_t pid = fork();
    if(pid > 0) {
        // 父进程
        printf("i am parent process, pid : %d\n", getpid());

        // 关闭写端
        close(pipefd[1]);
        
        // 从管道的读取端读取数据
        char buf[1024] = {0};

        while(1) {
            int len = read(pipefd[0], buf, sizeof(buf));
            printf("len : %d\n", len);
            printf("parent recv : %s, pid : %d\n", buf, getpid());
            memset(buf, 0, 1024);
        }

    } else if(pid == 0){
        // 子进程
        printf("i am child process, pid : %d\n", getpid());
        // 关闭读端
        close(pipefd[0]);
        char buf[1024] = {0};
        while(1) {
            // 向管道中写入数据
            char * str = "hello,i am child";
            write(pipefd[1], str, strlen(str));
            sleep(10);
        }
        
    }
    return 0;
}

在这里插入图片描述

那么怎么设置在子进程睡眠时,管道不阻塞,父进程仍然可以从管道中读取数据呢(也就是read非阻塞)?代码和结果如下,可以看到,即使管道中没有数据了,父进程的读端也没有堵塞,而是继续读,只不过为空。

#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
/*
    设置管道非阻塞
    int flags = fcntl(fd[0], F_GETFL);  // 获取原来的flag
    flags |= O_NONBLOCK;            // 修改flag的值
    fcntl(fd[0], F_SETFL, flags);   // 设置新的flag
*/
int main() {

    // 在fork之前创建管道
    int pipefd[2];
    int ret = pipe(pipefd);
    if(ret == -1) {
        perror("pipe");
        exit(0);
    }

    // 创建子进程
    pid_t pid = fork();
    if(pid > 0) {
        // 父进程
        printf("i am parent process, pid : %d\n", getpid());

        // 关闭写端
        close(pipefd[1]);
        
        // 从管道的读取端读取数据
        char buf[1024] = {0};

        int flags = fcntl(pipefd[0], F_GETFL);  // 获取原来的flag
        flags |= O_NONBLOCK;            // 修改flag的值
        fcntl(pipefd[0], F_SETFL, flags);   // 设置新的flag

        while(1) {
            int len = read(pipefd[0], buf, sizeof(buf));
            printf("len : %d\n", len);
            printf("parent recv : %s, pid : %d\n", buf, getpid());
            memset(buf, 0, 1024);//这一行是负责清空数组内容,否则的话即使管道为空,每次打印仍会打印数组的内容 
            sleep(1);
        }

    } else if(pid == 0){
        // 子进程
        printf("i am child process, pid : %d\n", getpid());
        // 关闭读端
        close(pipefd[0]);
        char buf[1024] = {0};
        while(1) {
            // 向管道中写入数据
            char * str = "hello,i am child";
            write(pipefd[1], str, strlen(str));
            sleep(5);
        }
        
    }
    return 0;
}

在这里插入图片描述

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

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

相关文章

Shapefile在线查看利器【MapJS】

MapJS是一个免费的GIS地图文件在线查看工具&#xff0c;在浏览器里即可直接打开本地的Shapfile、GeoJSON、TopoJSON、KML等文件进行查看。 MapJS在线访问地址&#xff1a;Shapefile|GeoJSON|KML在线查看工具 。 1、MapJS快速上手 在浏览器中打开MapJS官网后&#xff0c;直接拖…

计算机图形学 | 奇妙的真实感——片元着色

计算机图形学 | 奇妙的真实感——片元着色 计算机图形学 | 奇妙的真实感——片元着色9.1 图形渲染与视觉外观图形渲染的光栅化阶段基于视觉外观的渲染视觉物理现象视觉现象光照计算着色方式表面细节有光有影才有真实感 9.2 奇妙的颜色什么是颜色可见光谱颜色视觉的生理基础 人眼…

美颜sdk的多平台适配与跨平台开发技术分享

美颜sdk作为互联网时代的重要工具&#xff0c;也因其高效、稳定、易用的特点&#xff0c;被越来越多的应用开发者所采用。然而&#xff0c;在不同的平台上使用美颜sdk时&#xff0c;会遇到一些问题&#xff0c;如何进行多平台适配和跨平台开发&#xff0c;成为了一个值得探讨的…

只需要两步就能快速接入GPT

缘起 最近一个朋友提出&#xff0c;让我出个关于如何快速接入GPT的教程&#xff0c;今天就给大家安排上。 需要的工具 经过实测&#xff0c;这是迄今为止最便捷的接入方式&#xff0c;而且亲测有效。 首先&#xff0c;第一步你需要下载最新版的微软Edge浏览器&#xff0c;去…

Python(Keras)实现 LSTM 对销售额的预测

博主之前有涉及过LSTM的文章&#xff0c;见下&#xff1a; LSTM-理解 Part-1&#xff08;RNN&#xff1a;循环神经网络&#xff09; Python LSTM时序数据的预测&#xff08;一些数据处理的方法&#xff09; 机器学习 Pytorch实现案例 LSTM案例&#xff08;航班人数预测&#xf…

Unity3D :重要的类 - Gizmos 和 Handles

推荐&#xff1a;将 NSDT场景编辑器加入你的3D工具链 3D工具集&#xff1a; NSDT简石数字孪生 重要的类 - Gizmos 和 Handles Gizmos 和 Handles 类用于在 Scene 视图和 Game 视图绘制线条和形状以及交互式手柄和控件。这两个类共同提供了一种方法来扩展这些视图中显示的内容&…

【云原生】Kubernetes 的组件与架构

文章目录 引语1、集群组件1.1 控制平面组件&#xff08;Control Plane Components&#xff09;1.2 Node 组件1.3 插件&#xff08;Addons&#xff09; 2、集群搭建总结 引语 在上篇文章&#xff0c;我们介绍了 Kubernetes 是什么&#xff0c;它能够对容器进行编排&#xff0c;…

实现Qwidget窗口填满整个主窗口,并跟随鼠标的拖动自动缩放

实现Qwidget窗口填满整个主窗口&#xff0c;并跟随鼠标的拖动自动缩放 新建一个窗口&#xff0c;我想在这个窗口上放一个QWidget&#xff0c;并且这个QWidget能够布满整个窗口&#xff0c;还可以随着随鼠标的拖动自动缩放 1、首先给大家介绍一个好用的组件库&#xff1a;qt-mat…

lighthouse尘埃粒子计数器3100/3350参数资料

​​SOLAIR 3350集成了我们的超长寿命激光二极管技术传感器&#xff0c;可生产业界比较长的激光二极管寿命20年以上(基于连续24/7运行)。使用一个新的&#xff0c;更轻的延长寿命的电池和外部交流适配器&#xff0c;SOLAIR 3350更加便携。SOLAIR 3350具有业界最好的用户界面(UI…

springboot+java拍卖竞拍网站系统idea

书画拍卖网站系统的设计与实现的设计思想如下&#xff1a; Spring Boot 是 Spring 家族中的一个全新的框架&#xff0c;它用来简化Spring应用程序的创建和开发过程。也可以说 Spring Boot 能简化我们之前采用SSM&#xff08;Spring MVC Spring MyBatis &#xff09;框架进行…

10个学习Python的理由以及Python的优势有哪些?

Python的由来 Python的创始人是吉多范罗苏姆&#xff0c;1989年他在阿姆斯特丹的CWI工作&#xff0c;圣诞节期间&#xff0c;吉多范罗苏姆为了打发圣诞节的无聊&#xff0c;决定开发一个新的脚本解释程序&#xff0c;作为ABC 语言的一种继承。之所以选择Python作为编程语言的名…

新星计划|记录安装Nodejs和HBuilderX搭建、部署微信小程序开发环境(一)

文章目录 1 前言2 注册小程序账号3 安装微信开发者工具4 安装Nodejs和HBuilderX4.1 windows用户安装Nodejs4.2 macos/linux用户安装Nodejs4.3 安装HBuilder X 5 创建项目5.1 新建一个项目5.2 进行基本配置 6 HBuilderX同步微信开发者工具6.1 打开服务端口6.2 调用微信开发者工具…

不能使用ChatGPT 试试基于2021模型的 Claude (原GPT团队二次创业产品)聊天机器人 更详细的解答

大家过程中遇到问题都可以私信我 注册方式&#xff0c;引用别人的&#xff1a;用不了chatgpt&#xff0c;试试Claude-Claude注册教程_大数据食铁兽的博客-CSDN博客 不过上面作者没有写坑&#xff0c;只支持少部分国家&#xff08;我选用的日本&#xff0c;Claude官网会提示你…

【HarmonyOS】这些HarmonyOS应用开发的问题你都了解吗?

【关键字】 HTTP请求、requests exceeds 100、DNS域名解析、屏幕分辨率、ArkTS/JS 【问题描述1】 HTTP多次请求之后出现请求异常如何解决&#xff1f; 描述&#xff1a;接口是正常的&#xff0c;http多次请求出现提示“The requested has been canceled or the number of re…

mysql高阶语句与连接存储

文章目录 一、mysql高阶语句1.按照关键字进行排序2.多字段排序3.对查询的结果进行分组4.限制结果条目5.设置别名&#xff08;alias----》as&#xff09; 二、mysql连接与存储1.、连接查询2.存储过程 总结 一、mysql高阶语句 1.按照关键字进行排序 ​使用select语句可以将需要…

古鱼、恐龙和大众,相逢在百度百科的“彩虹桥”

提起孩子的天性&#xff0c;我们会想到什么&#xff1f; 首先是好奇心。 如果没有好奇心和求知欲作为动力&#xff0c;人类不可能产生那些给社会带来巨大价值的发明创造。对于个人来说&#xff0c;带着对万物的好奇&#xff0c;了解大千世界的丰富多彩&#xff0c;以后无论遇到…

Docker基础篇(上)

1、为什么Docker比VM快 2、帮助启动类命令 启动类命令 启动docker&#xff1a; systemctl start docker停止Docker&#xff1a; systemctl stop docker重启Docker&#xff1a; systemctl restart docker查看状态&#xff1a; systemctl status docker设置开机自启&#x…

【C++】20.异常

1.C语言处理错误方式 终止程序&#xff0c;如assert&#xff0c;缺陷&#xff1a;用户难以接受。如发生内存错误&#xff0c;除0错误时就会终止程序。返回错误码&#xff0c;缺陷&#xff1a;需要程序员自己去查找对应的错误。如系统的很多库的接口函数都是通过把错误码放到er…

【003】C++数据类型之整型类型(int)详解

C数据类型之整型变量详解 引言一、常量和变量二、整形常量三、整形变量的定义四、整型变量的初始化五、整型变量的声明5.1、C 变量的定义、变量的声明、变量的使用三者的关系 六、键盘&#xff08;输入设备&#xff09;给变量赋值七、案例&#xff1a;键盘获取两个int数值然后求…

win11+VS2019下配置PCL1.11.1

1、PCL安装配置 下载pcl-1.11.1-pdb-msvc2019-win64与PCL-1.11.1-AllInOne-msvc2019-win64.exe文件。以管理员身份运行PCL-1.11.1-AllInOne-msvc2019-win64.exe程序&#xff0c;截图如下&#xff1a; 安装过程中没有弹出OpenNI2的安装&#xff0c;但是要安装在3rdParty下&#…