【Linux】————进程间通信(匿名管道)

 9efbcbc3d25747719da38c01b3fa9b4f.gif

                                                      作者主页:     作者主页

                                                      本篇博客专栏:Linux

                                                      创作时间 :2024年6月20日

9efbcbc3d25747719da38c01b3fa9b4f.gif

进程间通信的目的:

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

进程间通信的发展

  • 管道
  • System V进程间通信
  • POSIX进程间通信

进程间通信的前提就是先让不同的进程看到同一份(操作系统)资源(一段内存),进程间通信一定是某个进程先需要通信,让OS创建一个共享资源,此时OS必须提供很多系统调用,OS创建的共享资源的不同,系统调用的接口也就不同,所有进程的通信会有不同的种类

进程间通信分类

管道:

  • 匿名管道
  • pipe管道

System V IPC

  • System V 消息队列
  • System V 共享内存
  • System V 信号量

POSIX IPC 

  • 消息队列
  • 共享内存
  • 信号量
  • 互斥量
  • 条件变量
  • 读写锁 

管道 

匿名管道:

一个进程将同一个文件打开两次,一次以写方式打开,另一次以读方式打开。此时会创建两个struct file,而文件的属性会共用,不会额外创建。

如果此时有创建了子进程,子进程会继承父进程的文件描述表,指向同一个文件,我们把上面分子进程都看到的文件,叫做管道文件,管道只允许单向通信,管道里的内容不需要刷新的磁盘。

未来要用父进程写,子进程读的话,在fork之后,各自关闭掉不用的文件描述符即可。 不用的描述符建议关闭,因为未来可能会误用,或者导致文件描述符泄露。

功能:创建匿名管道

参数:

pipefd[2]:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端。它是输出型参数。

返回值:成功返回0,失败返回错误代码

匿名管道的特性

  1.  面向字节流

  2. 用来进行具有血缘关系的进程,进行进程间通信(IPC)

  3. 文件的生命周期,随进程!管道也是!

  4. 单行的数据通信

  5. 管道自带同步互斥等保护机制!(同步互斥就是指对于同一个管道,同一时刻只允许一个进程或者线程进行操作,对于保证管道的正确性和稳定性都非常重要它使得多个进程或者线程在有序安全的前提下去利用管道进行有效的数据传输和通信)

使用管道通信的demo 

 上图是创建管道,pipe的使用的例子。

下面是测试的完整代码:

#include <iostream>
#include <unistd.h>
#include <string>
#include <cstdlib>
#include <sys/types.h>
#include <wait.h>using namespace std;// Father -> read
// child -> write
int main()
{int fds[2] = {0};int n = pipe(fds); // fds输出型参数if (n != 0){cerr << "pipe error" << endl; // cerr打印错误消息,属于2号,而cout属于标准输出,2是标准错误}pid_t id = ::fork();if (id < 0){cerr << "fork error" << endl;return 2;}else if (id == 0){// 子进程// 关闭不需要的fd// 系统函数尽量带上::做区分// 一般f[0]代表管道的读端,f[1]代表着写端::close(fds[0]);int cnt = 0;while (true){// 子进程写入string message = "hello bit,hello ";message += to_string(getpid());message += ", ";message += to_string(cnt);// fds[1]::write(fds[1], message.c_str(), message.size());cnt++;sleep(1);//break;}exit(0);}else{// 父进程// 关闭不需要的fd::close(fds[1]);// 从管道里读char buffer[1024];while (true){ssize_t n = ::read(fds[0], buffer, 1024);if (n > 0){buffer[n] = 0;cout << "child -> father " << buffer << endl;}else if (n == 0){//如果写段关闭//读端读完管道内部的数据,在读取的时候就会收到返回值0,标识对端关闭,也表示读到的文件结尾cout << "n:" << n << endl;cout << "child quit? me too" << endl;//break;}close(fds[0]);break;cout<<endl;}int status = 0;pid_t rid = waitpid(id, nullptr, 0);cout << "father wait child success" << rid << "exit code" << ((status<<8)&0xFF) << ",exit sig:"<<(status&0x7F) << endl;}return 0;
}

管道的四种情况:

  1. 如果此时管道是空的,并且写段fd还没有关闭,此时读取条件不具备,都进程会被阻塞,读进程会等待,直到写段写入数据
  2. 如果管道被写满,并且读端fd不读且没有关闭,此时写进程会被阻塞,知道数据被读取
  3. 如果读端一直在读,并且写段关闭了wfd,读端read返回值会读到0,表示读到文件结尾
  4. 如果读端rfd直接关闭,写段wfd一直写入,那么写端会被OS直接用13信号关闭掉,相当于进程出现了异常

进程池的实现:

hpp:

Processplool.hpp:

#include <iostream>
#include <string>
#include <stdlib.h>
#include <vector>
#include <unistd.h>
#include <sys/types.h>
#include <functional>
#include <sys/wait.h>
#include "Task.hpp"
#include "Channel.hpp"using work_t = std::function<void()>;
using namespace std;// const int num = 5;enum
{OK,UsageError,PipeError,ForkError
};// 子进程干活
void Worker()
{// 子进程干的活while (true){int cmd = 0;int n = ::read(0, &cmd, sizeof(cmd));if (n == sizeof(cmd)){tm.Excute(cmd);// cout << "cmd:" << cmd << endl;}else if (n == 0){cout << "pid:" << getpid() << " quit..." << endl;break;}else{cout << "读取操作发生错误" << endl;}}
}class ProcessPool
{
public:ProcessPool(int n, work_t w): processnum(n), work(w){}// 调试打印函数void DebugPrint(){for (const auto &c : channels){cout << c.Name() << endl;}}int InitProcesspool(){for (int i = 0; i < processnum; i++){int pipefd[2] = {0};int n = pipe(pipefd);if (n < 0){cerr << "pipe errno" << endl;return 2;}pid_t id = fork();if (id < 0)return 3; // 创建子进程失败// 建议通信通道if (id == 0){::close(pipefd[1]);   // 读取::dup2(pipefd[0], 0); // 让子进程直接从0里面读// 子进程Worker();::exit(0);}// 父进程::close(pipefd[0]);                   // writechannels.emplace_back(pipefd[1], id); // 自动创建一个管道并且放进channels中}return OK;}void DispatchTask(){int num = 20;// 派发任务int who = 0;while (num--){// 1、选择一个任务int task = tm.SelectTask();// b、选择一个子进程Channel &curr = channels[who++];who %= channels.size();cout << "############################" << endl;cout << "send:" << task << " to " << curr.Name() << ",任务还剩:" << num << endl;cout << "############################" << endl;// c、派发任务curr.Send(task);sleep(1);}}void CleanProceePool(){// 3.退出进程池for (auto &x : channels){x.Close(); // 关闭}for (auto &x : channels){pid_t rid = ::waitpid(x.Id(), nullptr, 0);if (rid > 0){cout << "child" << rid << "wait success.." << endl;}}}private:vector<Channel> channels;work_t work;int processnum;
};

Task.hpp

#pragma once#include <iostream>
#include <unordered_map>
#include <functional>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>using namespace std;
using task_t = function<void()>;void Download()
{cout << "我是下载任务" << "pid:" << getpid() << endl;
}
void Log()
{cout << "我是日制任务" << "pid:" << getpid() << endl;
}
void Sql()
{cout << "我是数据库同步任务" << "pid:" << getpid() << endl;
}static int number = 0;
class TaskManger
{
public:TaskManger(){srand(time(nullptr));InsertTask(Download);InsertTask(Log);InsertTask(Sql);}void InsertTask(task_t t){tasks[number++] = t;}void Excute(int number){if (tasks.find(number) == tasks.end())return;tasks[number]();}int SelectTask(){return rand() % number;}~TaskManger(){}private:unordered_map<int, task_t> tasks;
};TaskManger tm;

Channel.hpp

#ifndef __CHANNEL_HPP_
#define __CHANNEL_HPP_
#include<iostream>
#include<unistd.h>
#include<string.h>
using namespace std;
// 先描述再组织
class Channel
{
public:Channel(int wfd, pid_t who) : _wfd(wfd), _who(who){_name = "Channel- " + to_string(wfd) + " - " + to_string(who);}string Name() const{return _name;}void Send(int cmd){::write(_wfd, &cmd, sizeof(cmd));}void Close(){::close(_wfd);}pid_t Id(){return _who;}~Channel(){// cout << "~Channel" << endl;}private:int _wfd;string _name;pid_t _who;
};#endif

Main.cc

#include "Processpool.hpp"
#include "Task.hpp"void Usage(string proc)
{cout << "Usage:" << proc << "process-num" << endl;
}int main(int argc, char *argv[])
{if (argc != 2){Usage(argv[0]);return 1;}try{int num = stoi(argv[1]);ProcessPool *pp=new ProcessPool(num,Worker);pp->InitProcesspool();//1.初始化pp->DispatchTask();   //2.轮询派发任务pp->CleanProceePool();//3.关闭进程// sleep(100);delete  pp;return 0;}catch (const std::invalid_argument &e){cerr << "命令行参数不是有效的整数形式: " << e.what() << endl;return 1;}catch (const std::out_of_range &e){cerr << "命令行参数超出整数表示范围: " << e.what() << endl;return 1;}
}

这里我们还要补充一个知识:

正如上图,其实我们每次创建一个子进程的时候,子进程都会继承父进程的文件描述符表,所以我们继承的时候,父进程中原本指向前面的管道的那个描述符也会被继承,这样就会有多个文件描述符指向那个进程,这样会导致后面想要在一个进程执行完任务后关闭他的时候无法关闭,所以我们需要在每次创建一个子进程之后关闭掉继承下来的写端

最后:

十分感谢你可以耐着性子把它读完和我可以坚持写到这里,送几句话,对你,也对我:

1.一个冷知识:
屏蔽力是一个人最顶级的能力,任何消耗你的人和事,多看一眼都是你的不对。

2.你不用变得很外向,内向挺好的,但需要你发言的时候,一定要勇敢。
正所谓:君子可内敛不可懦弱,面不公可起而论之。

3.成年人的世界,只筛选,不教育。

4.自律不是6点起床,7点准时学习,而是不管别人怎么说怎么看,你也会坚持去做,绝不打乱自己的节奏,是一种自我的恒心。

5.你开始炫耀自己,往往都是灾难的开始,就像老子在《道德经》里写到:光而不耀,静水流深。

最后如果觉得我写的还不错,请不要忘记点赞✌,收藏✌,加关注✌哦(。・ω・。)

愿我们一起加油,奔向更美好的未来,愿我们从懵懵懂懂的一枚菜鸟逐渐成为大佬。加油,为自己点赞!

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

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

相关文章

Android [调试方法]如何在编译日志中快速找出报错信息

问题描述&#xff1a; 在进行Android完整编译时&#xff0c;经常遇到各种编译导致编译失败的情况&#xff0c;但其日志信息的打印数量十分巨大&#xff0c;无法仔细阅读逐行阅读。对于不熟悉的方法的同学定位报错问题的位置往往需要耗费较长时间。因此本作者将较为典型的方法总…

论文阅读:Computational Long Exposure Mobile Photography (一)

这篇文章是谷歌发表在 2023 ACM transaction on Graphic 上的一篇文章&#xff0c;介绍如何在手机摄影中实现长曝光的一些拍摄效果。 Abstract 长曝光摄影能拍出令人惊叹的影像&#xff0c;用运动模糊来呈现场景中的移动元素。它通常有两种模式&#xff0c;分别产生前景模糊或…

将 IBM WatsonX 数据与 Milvus 结合使用,构建用于知识检索的智能 Slack 机器人

在当今快节奏的工作环境中&#xff0c;快速轻松地访问信息对于保持生产力和效率至关重要。无论是在 Runbook 中查找特定说明&#xff0c;还是访问关键知识转移 &#xff08;KT&#xff09; 文档&#xff0c;快速检索相关信息的能力都可以产生重大影响。 本教程将指导您构建一个…

法律智能助手:开源NLP系统助力法律文件高效审查与检索

一、系统概述 思通数科AI平台是一款融合了自然语言处理和多标签分类技术的开源智能文档分类工具&#xff0c;特别适用于法律行业。平台采用深度学习的BERT模型来进行特征提取与关系抽取&#xff0c;实现了精准的文档分类和检索。用户可以在线训练和标注数据&#xff0c;使系统…

在linux系统中安装pygtftk软件

1.下载和安装 网址&#xff1a; https://dputhier.github.io/pygtftk/index.html ## 手动安装 git clone http://gitgithub.com:dputhier/pygtftk.git pygtftk cd pygtftk # Check your Python version (>3.8,<3.9) pip install -r requirements.txt python setup.py in…

Kubernetes:(三)Kubeadm搭建K8s 1.20集群

文章目录 一、Kubeadm安装流程二、实验1.环境准备2.所有节点安装kubeadm&#xff0c;kubelet和kubectl&#xff08;除了Harbor节点&#xff09;3.部署 Dashboard4.安装Harbor私有仓库 一、Kubeadm安装流程 集群名称IP地址安装软件master&#xff08;2C/4G&#xff0c;cpu核心数…

前端之html(二)加入css开篇(一)

1.lebal标签-增大点击范围 性别:<input type"radio" name"gender" id"man"><lebal for"man">男</lebal> <lebal><input type"radio" name"gender" id"nv">女</leba…

记一次:Clickhouse同步mysql数据库

ClickHouse可以通过使用MaterializeMySQL引擎来实现与MySQL的数据同步。 前言&#xff1a;因为数据量比较大&#xff0c;既然要分库&#xff0c;为何不让clickhouse同步一下mysql数据库呢&#xff1f; 零、前期准备--mysql的查询和配置 1 查询mysql的配置状态 查询以下语句…

Rust 力扣 - 1984. 学生分数的最小差值

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 原数组 nums 排序&#xff0c;遍历nums中下标为[0, nums.len() - k]的学生分数 假设当前遍历的下标为i则&#xff0c;以 i 下标为最小值的学生分数的最小差值为nums[i k - 1] - nums[i] 取最小差值的最小值即…

10个领先的增强现实平台【AR】

增强现实 (AR) 被描述为一种通过计算机生成的内容增强现实世界的交互式体验。 使用软件、应用程序和硬件&#xff08;例如 AR 眼镜&#xff09;&#xff0c;AR 能够将数字内容叠加到现实环境和物体上。早在 2024 年&#xff0c;许多像 Apple 这样的公司就已进入 VR/AR 市场&am…

提高交换网络可靠性之端口安全配置

转载请注明出处 此实验为配置交换机端口安全&#xff0c;当非法设备接入接口时自动触发安全措施 1.查看PC1和PC2的MAC地址&#x1f447; 2.交换机改名为S1&#xff0c;同时启用端口安全 3.配置允许接入设备 4.设置违规处理方式&#xff1a;即违规则关闭端口 5.查看安全端口相关…

HTTP与HTTPS的区别

HTTP与HTTPS的区别 一、HTTP二、HTTPS三、区别 一、HTTP HTTP (HyperText Transfer Protocol)&#xff0c;即超文本运输协议&#xff0c;是实现网络通信的一种规范 在计算机和网络世界有&#xff0c;存在不同的协议&#xff0c;如广播协议、寻址协议、路由协议等等… 而HTTP…

Qt中的Model与View5: QStyledItemDelegate

目录 QStyledItemDelegate API 重载公共函数 保护函数 重载保护函数 当在 Qt 项目视图中显示模型数据时&#xff0c;例如 QTableView&#xff0c;每个项目由代理绘制。此外&#xff0c;当项目被编辑时&#xff0c;提供一个编辑器小部件&#xff0c;该小部件在编辑时显示在项…

token无感刷新+处理并发的后端方案

问题描述&#xff1a; 当用户通过登陆后进入一个web网站&#xff0c;会把token保存到localStorage。假设token过期时间30min。 那么当用户在网站快乐地玩耍了30min后&#xff0c;这时进行了一次提交表单&#xff0c;它会被重定向到登陆页面。 作为用户&#xff1a;我表单填了…

VMware虚拟机Debian扩展磁盘

一、 版本 VMware&#xff1a;Workstation 17 Pro虚拟机&#xff1a;Debian11 二、 VMware虚拟机扩展 虚拟机关机状态快照或者备份&#xff1a;以免扩容失败导致文件丢失虚拟机——设置——硬盘——磁盘使用工具——扩展——扩展磁盘容量——设置为想要的大小 三、 虚拟机…

L1-2 什么是机器学习

L1-2 什么是机器学习 作者 陈越 单位 浙江大学 什么是机器学习&#xff1f;上图展示了一段面试官与“机器学习程序”的对话&#xff1a; 面试官&#xff1a;9 10 等于多少&#xff1f; 答&#xff1a;3 面试官&#xff1a;差远了&#xff0c;是19。 答&#xff1a;16 面试…

ssm基于WEB的人事档案管理系统的设计与实现+jsp

系统包含&#xff1a;源码论文 所用技术&#xff1a;SpringBootVueSSMMybatisMysql 免费提供给大家参考或者学习&#xff0c;获取源码请私聊我 需要定制请私聊 目 录 1 绪论 1 1.1 选题背景 1 1.2 选题意义 1 1.3 研究内容 2 2 系统开发技术 3 2.1 MySQL数据库 3 2.…

WireShark入门学习笔记

学习视频&#xff1a;WireShark入门使用教程 文章目录 WireShark介绍WireShark抓包入门操作WireShark过滤器使用WireShark之ARP协议分析WireShark之ICMP协议TCP连接的3次握手协议TCP连接断开的4次挥手协议WireShark抓HTTP协议黑客利用WireShark获取用户密码实战 WireShark介绍…

vue3中使用mqtt数据传输(封装)

使用版本 "mqtt": "^5.8.0",安装指令 npm install mqtt --save ------ yarn add mqtt介绍mqtt 参考使用文档 配置 connection: {protocol: "ws",host: "broker.emqx.io",port: 8083,endpoint: "/mqtt",clean: true,con…

《Baichuan-Omni》论文精读:第1个7B全模态模型 | 能够同时处理文本、图像、视频和音频输入

技术报告Baichuan-Omni Technical ReportGitHub仓库地址 文章目录 论文摘要1. 引言简介2. 训练2.1. 高质量的多模态数据2.2. 多模态对齐预训练2.2.1. 图像-语言分支2.2.2. 视频语音分支2.2.3. 音频语言分支2.2.4. 图像-视频-音频全方位对齐 2.3. 多模态微调监督 3. 实验3.1. 语…