进程间通信之匿名管道(pipe)

news2025/1/11 7:57:00

文章目录

  • 前言
  • 管道
    • 管道的创建
    • 管道的使用
      • 单进程使用管道进行通信
      • 多进程使用管道进行通信
      • 关闭管道的读端/写端
  • 总结

在这里插入图片描述

前言

管道分为匿名管道和命名管道,匿名管道只能在有共同祖先的(有亲缘关系)进程中使用,而命名管道可以在任意进程中使用,以下的“管道”指的都是匿名管道命名管道的知识后续再进行更新


管道

IPC (进程间通信)有多种方式, 管道是IPC的最基本的方式。管道是“半双工”的,即是单向的。管道是FIFO(先进先出)的。
单进程中的管道:int fd[2]
1、使用文件描述符fd[1], 向管道写数据
2、使用文件描述符fd[0], 从管道读数据
在这里插入图片描述
管道的局限性:
①数据一旦被读走,便不在管道中存在,不可反复读取。
②由于管道采用半双工通信方式。因此,数据只能在一个方向上流动。
③只能在有公共祖先的进程间使用管道。


管道的创建

在这里插入图片描述
参数:
一个大小为2的fd数组
返回值:
成功:返回 0
失败:返回 -1


注意:获取两个“文件描述符”分别对应管道的读端和写端。
1、fd[0]: 是管道的读端
2、fd[1]: 是管道的写端
如果对fd[0]进行写操作,对fd[1]进行读操作,可能导致不可预期的错误。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(void) 
{
	int fd[2];
	int ret;
	ret = pipe(fd);
	....
	....
}

管道的使用

管道虽然可以在单进程中使用,但是其实没啥用处,更多地是在多进程的环境下使用,不过既然写了,也都举个例子吧!


单进程使用管道进行通信

创建管道后,获得该管道的两个文件描述符,不需要普通文件操作中的open操作
在这里插入图片描述
直接看代码吧,挺简单的👇

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(void) 
{
	int fd[2];
	int ret;
	char buff1[1024];
	char buff2[1024];

	ret = pipe(fd);
	if (ret !=0) {
		printf("create pipe failed!\n");
		exit(1);
	}

	strcpy(buff1, "Hello!");
    //写数据一定是在fd[1]中写
	write(fd[1], buff1, strlen(buff1)); 
	printf("send information:%s\n", buff1);
    //将buff2清零
	bzero(buff2, sizeof(buff2));
    //读数据一定是在fd[0]中写
	read(fd[0], buff2, sizeof(buff2));
	printf("received information:%s\n", buff2);

	return 0;	
}

运行结果:
在这里插入图片描述


多进程使用管道进行通信

由于管道的通信是半双工的(数据只能由一端流到另外一端,而不能反过来发送数据),所以如果要在多进程中使用管道进行通信的话,一般是创建两个管道,这样就可以更清晰相互发送数据了(而不是说一个管道不能用来相互发送数据),采用父子进程的时候,子进程会“复制”父进程的资源,这样就有了2个fd[2]了,虽然名字一样,但是表示的不是同个fd[2],但是又可以相互通信(可以理解成虽然复制成了两个管道,但是两个管道是相通的,各个进程持有一个写端和读端)。
在这里插入图片描述

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(void) 
{
	int fd[2];
	int ret;
	char buff1[1024];
	char buff2[1024];
	pid_t pd;

	ret = pipe(fd);
	if (ret !=0) {
		printf("create pipe failed!\n");
		exit(1);
	}
    //fork一个子进程
	pd = fork();
	if (pd == -1) {
		printf("fork error!\n");
		exit(1);
	} else if (pd == 0) {
        //子进程正确返回的pid会是0所以子进程执行这段代码
        //读数据
		bzero(buff2, sizeof(buff2));
		read(fd[0], buff2, sizeof(buff2));
		printf("child process(%d) received information:%s\n", getpid(), buff2);
        sleep(5);
        //写数据
        strcpy(buff1, "Hello! father!");
		write(fd[1], buff1, strlen(buff1)); 
		printf("child process(%d) send information:%s\n", getpid(), buff1);
	} else {
        //父进程返回子进程的pid。所以父进程执行这段代码
        //写数据
		strcpy(buff1, "Hello! child!");
		write(fd[1], buff1, strlen(buff1)); 
		printf("parent process(%d) send information:%s\n", getpid(), buff1);
        sleep(5);
        //读数据
        bzero(buff2, sizeof(buff2));
		read(fd[0], buff2, sizeof(buff2));
		printf("parent process(%d) received information:%s\n", getpid(), buff2);
	}
    close(fd[0]);
    close(fd[1]);
    //等待子进程执行完
	if (pd > 0) {
		wait();
	}
	
	return 0;	
}

运行结果:
在这里插入图片描述


关闭管道的读端/写端

此类示例的主要应用场景是:
1、如果不准备再向管道写入数据,则把该管道的所有写端都关闭,则,此时再对该管道read时,就会返回0,而不再阻塞该读操作。(管道的特性)
注意,这是管道的特性。
如果有多个写端口,而只关闭了一个写端,那么无数据时读操作仍将被阻塞。

2、多个进程通信的时候,我只想要单方向的数据流动

父子进程各有一个管道的读端和写端;
1、把父进程的读端(或写端)关闭;
2、把子进程的写端(或读端)关闭;
使这个“4端口”管道变成单向的“2端口”管道(虽然复制成了两个管道,但是两个管道是相通的,各个进程持有一个写端和读端,如果在两方的端口各关闭一个的话,那么就又会变成一个单方向的数据流动),如图:
在这里插入图片描述

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(void) 
{
	int fd[2];
	int ret;
	char buff1[1024];
	char buff2[1024];
	pid_t pd;

	ret = pipe(fd);
	if (ret !=0) {
		printf("create pipe failed!\n");
		exit(1);
	}

	pd = fork();
	if (pd == -1) {
		printf("fork error!\n");
		exit(1);
	} else if (pd == 0) {
		//子进程关闭写端
		close(fd[1]);
		bzero(buff2, sizeof(buff2));
		read(fd[0], buff2, sizeof(buff2));
		printf("process(%d) received information:%s\n", getpid(), buff2);
	} else {
		//关闭读端
		close (fd[0]);
		strcpy(buff1, "Hello!");
		write(fd[1], buff1, strlen(buff1)); 
		printf("process(%d) send information:%s\n", getpid(), buff1);
		
		close (fd[1]);		
	}

	if (pd > 0) {
		wait();
	}
	
	return 0;	
}

运行结果:
在这里插入图片描述

总结

这篇文章到此结束,非常感谢您能看到这,这篇文章还不够详细,我也将持续更新,希望这篇文章能够对您有所帮助,当然,如果对于本文有任何的疑问也请在评论区中提出来,感谢您的观看!!
在这里插入图片描述

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

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

相关文章

【youcans动手学模型】目标检测之 OverFeat 模型

欢迎关注『youcans动手学模型』系列 本专栏内容和资源同步到 GitHub/youcans 【youcans动手学模型】目标检测之 OverFeat 模型 1. OverFeat 卷积神经网络模型1.1 论文摘要1.2 技术背景1.3 基本方法模型设计多尺度分类滑动窗口&#xff08;Sliding window&#xff09;定位&#…

ACL—访问控制列表

目录 ACL的分类&#xff1a; 配置 配置基础ACL &#xff1a; 例一&#xff1a; 例二&#xff1a; 配置高级ACL &#xff1a; 例一&#xff1a; 例二&#xff1a; ACL—访问控制列表 配置了ACL的网络设备根据事先制定号的规则&#xff0c;然后对经过该设备的流量按照对应的规…

访问者模式:灵活处理对象结构

访问者模式&#xff1a;灵活处理对象结构 在软件开发中&#xff0c;我们经常会遇到处理复杂对象结构的情况。对象结构由多个不同类型的对象组成&#xff0c;而每个对象都可能具有不同的行为。此时&#xff0c;访问者模式可以派上用场。访问者模式是一种行为设计模式&#xff0…

接口的幂等性如何设计

前言 所谓幂等: 多次调用方法或者接口不会改变业务状态&#xff0c;可以保证重复调用的结果和单次调用的结果一致。 我们在开发中主要操作也就是CURD,其中读取操作和删除操作是天然幂等的&#xff0c;我们所关心的就是创建操作、更新操作。 创建操作一定是非幂等的因为要涉及…

JVM包含哪几部分?JVM内存模型?线程的生命周期? 对Spring AOP的理解?布隆过滤器

目录 1. JVM包含哪几部分2. JVM内存模型3. 双亲委派模型4. Java内存模型5. Serializable接口为什么需要定义serialVersionUID常量6. 线程的生命周期7. 什么是MVC8. volatile关键字的理解9. 对Spring AOP的理解10. 布隆过滤器 1. JVM包含哪几部分 JVM由三部分组成&#xff1a;类…

WalkRE2019--构面流程

1、手动圈图 选中面层中的一般房屋面&#xff0c;双击&#xff0c;鼠标变成十字光标后&#xff0c;开始在图上圈出一个闭合形状。如下&#xff1a; 如上&#xff0c;完成一个一般房屋面的绘制。 2、加工菜单栏中的自动构面功能。 这里推荐点击构面方法&#xff0c;原因是操作起…

MachineLearningWu_13_AGI

AGI的全称是artificial general intelligence&#xff0c;通用人工智能&#xff0c;而我们现在做的关于医学影像的分析&#xff0c;可以说完全是ANI。 而我们使用MLP对于大脑中神经网络的模拟更是完全不同于人类大脑的行为。

mysql(三)InnoDB之自适应hash索引

目录 前言自适应哈希索引 (Adaptive Hash Index, AHI)既然是哈希&#xff0c;key 是什么&#xff0c;value 是什么&#xff1f;为啥叫 “自适应 (adaptive)****” 哈希索引&#xff1f;系统会不会判断失误&#xff0c;是不是一定能加速&#xff1f; 创建自定义的hash索引思路示…

华为申请注册盘古大模型商标;京东推出言犀大模型,率先布局产业应用

7月14日科技新闻早知道&#xff0c;一分钟速览。 1.华为申请注册盘古大模型商标&#xff1a; 据天眼查 App 显示&#xff0c;7 月 7 日&#xff0c;华为技术有限公司申请注册“华为云盘古”、“Huawei Cloud Pangu Models”文字及图形商标&#xff0c;国际分类为网站服务、社…

基础设施SIG月度动态:龙蜥官网新增CSDN第三方账号登录,内核CI新增测试任务停止功能

基础设施 SIG&#xff08;OpenAnolis Infra SIG&#xff09;目标&#xff1a;负责 OpenAnolis 社区基础设施工程平台的建设&#xff0c;包括官网、Bugzilla、Maillist、ABS、ANAS、CI 门禁以及社区 DevOps 相关的研发工程系统。 01 SIG 整体进展 1. 龙蜥社区官网与 CSDN dev…

管理大规模文件的挑战与解决方案

管理大规模文件是当今企业和组织面临的一项重要挑战。随着信息技术的迅速发展和数字化转型的推进&#xff0c;组织内外产生的文件数量呈指数级增长&#xff0c;如何高效地管理这些文件成为了亟待使用文件管理系统解决的问题。 挑战一&#xff1a;数据量巨大 随着企业和组织的…

基于STM32CUBEMX驱动TOF模块VL6180与VL6180X(5)----驱动多个VL6180X

基于STM32CUBEMX驱动TOF模块VL6180与VL6180X----5.驱动多个VL6180X 概述样品申请修改设备地址配置vl6180x主程序测试结果 概述 在本章中&#xff0c;我们将探讨如何同时驱动多个VL6180传感器进行距离测量。我们将介绍如何有效地管理多个传感器之间的通信和控制&#xff0c;以确…

❤️创意网页:创造精彩的登录体验-3D翻转登录页面

✨博主&#xff1a;命运之光 &#x1f338;专栏&#xff1a;Python星辰秘典 &#x1f433;专栏&#xff1a;web开发&#xff08;简单好用又好看&#xff09; ❤️专栏&#xff1a;Java经典程序设计 ☀️博主的其他文章&#xff1a;点击进入博主的主页 前言&#xff1a;欢迎踏入…

(9)基础强化:元字符,正则表达式,匹配,提取组,Regex,Match与Matches

一、作业 1、问&#xff1a;下面解压程序出错&#xff0c;什么原因&#xff1f; string src "E:\1.txt";string des "E:\2.txt";using (FileStream read File.OpenRead(src)){using (GZipStream gzip new GZipStream(read, CompressionMode.Decompress…

FPGA——按键控制led灯

文章目录 一、实验环境二、实验任务三、系统设计四、实验过程4.1 编写verilog代码4.2 引脚配置 五、仿真5.1 仿真代码5.2 仿真结果 六、实验结果七、总结 一、实验环境 quartus 18.1 modelsim vscode Cyclone IV开发板 二、实验任务 使用开发板上的四个按键控制四个LED灯。按…

“反AI斗士”马斯克进军AI,你怎么看?

“反AI斗士”马斯克进军AI&#xff0c;你怎么看&#xff1f; 当地时间7月12日&#xff0c;马斯克在Twitter上宣布&#xff1a;“xAI正式成立&#xff0c;去了解现实。”马斯克表示&#xff0c;推出xAI的原因是想要“了解宇宙的真实本质”。公司由马斯克本人亲自带队&#xff0c…

软件外包开发的原型图工具

在软件开发中需要用到原型图工具来将需求转化为图形界面&#xff0c;这样可以更好更准确的表达需求的实现方式。与传统的需求文档相比&#xff0c;原型图的表达更直接&#xff0c;不但可以画出UI&#xff0c;也支持UI之间的跳转连接&#xff0c;与最终的实现效果基本是一样的。…

【雕爷学编程】Arduino动手做(149)---MAX9814咪头传感器模块4

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…

如何在Windows 8和10中检查最后一次的启动模式

Windows 8、Windows 8.1 和 Windows 10 中的用户可以在 PC 上执行混合关机(快速启动)、完全关机或休眠。 快速启动(又名:hiberboot、混合启动或混合关机)在 Windows 中默认打开,是一种帮助你的电脑在关机后更快启动的设置。甚至比休眠还要快。 休眠是一种主要为笔记本电…

Linux下Nginx升级

nginx版本升级不会覆盖配置文件&#xff0c;但以防万一升级前请先备份配置文件或者配置文件夹 默认配置文件地址&#xff1a;/usr/local/nginx/conf/nginx.conf 1.下载 wget -c http://nginx.org/download/nginx-1.24.0.tar.gz 2.解压 tar -xvf nginx-1.24.0.tar.gz 3.nginx…