当前位置: 首页 > news >正文

进程间通信初识:管道

进程间通信

目的:多个进程协同,去完成一件事

  • 数据传输:一个进程需要将它的数据发送给另一个进程
  • 资源共享:多个进程之间共享同样的资源。
  • 通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
  • 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并知道他的状态改变了

定义

进程将自己的数据交给另一个进程

怎么做到的?

进程是有独立性的,你不可能直接读取另一个进程的数据,那是怎么做到的?

一般规律

所以内存中就有专门交换数据的空间这块空间要由操作系统来提供(一般由OS提供

具体做法

因为OS提供的空间有多种方式,所以就有了不同的通信方式

  1. 管道(匿名,命名)
  2. 共享内存
  3. 消息队列
  4. 信号量

文件描述符

我们要通过文件描述符来学习管道,先来复习一下
在这里插入图片描述

  1. 文件描述符是整数,有默认的三个(0、1、2)分别代表标准输入(键盘)、标准输出(显示器)、标准错误(显示器)
  2. file_struct 是个结构体 用于存储各个文件,其下标就是文件描述符
  3. 进程和文件之间,通过进程内部的*files 来指向file_struct,来管理文件
  4. 创建子进程的时候,需要将父进程的file_struct也给子进程一份,但父进程管理的文件不用拷贝给子进程,但内部的指针指向不变(仍指向原本的文件,是浅拷贝)

通过同一文件描述符指向同一个文件来实现在 不同进程中修改同一个文件,得到同一份资源的方式 就是管道
(同一个文件写入和读取是一个缓冲区
并且管道是单向管道

管道

了解完基本概念,我们就通过父子进程来进一步学习

让父进程来读取,子进程来写入
关掉父进程的写端和子进程的读端 这就实现了单向通信
这里解释了为什么进程要用读方式和写方式同时打开一个文件

并且由于struct file是由引用计数来决定是否释放的(记数为0再释放)
所以不用担心关闭端口会释放掉这个指针

在这里插入图片描述

pipe():匿名管道

操作系统提供了这个函数来进行管道通信

#include<unistd.h>
int pipe(int pipefd[2])
//pipefd是个输出型参数
//pipe创建了一个不需要向磁盘中刷新并且在磁盘中不存在的文件
//只能通过文件描述符找到,是个匿名文件(即匿名管道)

他的原理就是创建子进程继承父进程的资源,来实现共享资源
同理 父进程和兄弟进程,爷孙进程也可以通信(即在有血缘关系的进程间通信

代码展示

看一下用c是怎么使用管道的

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>void writer(int wfd)
{const char *str = "hello father, I am child";char buffer[128];int cnt = 0;pid_t pid = getpid();while(1){// 使用 snprintf 函数格式化字符串,将消息、进程 ID 和计数写入缓冲区snprintf(buffer, sizeof(buffer), "message: %s, pid: %d, count: %d\n", str, pid, cnt);// 将格式化后的字符串写入文件描述符 wfd,写入的字节数为字符串的长度write(wfd, buffer, strlen(buffer));cnt++;sleep(1);}
}
void reader(int rfd)
{char buffer[1024];while(1){// 从文件描述符 rfd 中读取数据,最多读取 sizeof(buffer)-1 字节到缓冲区 bufferssize_t n = read(rfd, buffer, sizeof(buffer)-1);// 强制转换并忽略返回值 n,表示不关心读取的字节数(void)n;printf("father get a message: %s", buffer);}
}int main()
{// 1. int pipefd[2];int n = pipe(pipefd);if(n < 0) return 1;printf("pipefd[0]: %d, pipefd[1]: %d\n", pipefd[0]/*read*/, pipefd[1]/*write*/); // 3, 4//默认第一个是读,第二个是写// 2. pid_t id = fork();if(id == 0){//child: wclose(pipefd[0]);//关闭子进程的读writer(pipefd[1]);exit(0);}// father: rclose(pipefd[1]);//关闭父进程的写reader(pipefd[0]);wait(NULL);return 0;
}

小结

下一篇文章继续介绍管道


http://www.mrgr.cn/news/60029.html

相关文章:

  • git的学习之远程进行操作
  • Oracle SQL语句 某字段重复数据只取一条
  • Depcheck——专门用于检测 JavaScript 和 Node.js 项目中未使用依赖项的工具
  • 凡客平台接口技术详解及代码示例
  • 第二十八节高斯模糊
  • 《云原生安全攻防》-- K8s攻击案例:权限维持的攻击手法
  • Atlas800昇腾服务器(型号:3000)—SwinTransformer等NPU推理【图像分类】(九)
  • 计算结构体及其中元素的大小
  • Semantic Kernel进阶:创建和管理聊天(ChatCompletion)历史记录对象(四)
  • Linux:认识文件
  • PCL 基于法向量夹角提出错误匹配点对
  • shodan4,挂黑网站查找,弱口令网站搜索
  • 图---java---黑马
  • 【H2O2|全栈】CSS案例章节(一)——圣杯布局和双飞翼布局
  • spring boot 整合Knife4j
  • 【最新】Kali Linux虚拟机安装与优化全攻略:必做设置让你事半功倍!
  • python print常见用法
  • 【鸿蒙开发 | 端云一体化 —— 开发app不要在为没有后端而烦恼了,端云一体化帮你完成一站式开发!】
  • 自动化结账测试:使用 Playwright确保电商支付流程的无缝体验【nodejs]
  • 【力扣】[Java版] 刷题笔记-101. 对称二叉树
  • MATLAB生物细胞瞬态滞后随机建模定量分析
  • 基础设施即代码(IaC):自动化基础设施管理的未来
  • ctfshow——web(持续更新)
  • 指数运算和幂运算
  • redis详细教程(3.hash和set类型)
  • 计算机网络——有连接传输层协议TCP