进程间通信基础知识【Linux】——上篇

目录

一,理解进程之间的通信

1. 进程间通信目的

2. 进程间通信的技术背景

3,常见的进程间通信

二,管道

1. 尝试建立一个管道

管道的特点:

管道提供的访问控制:

2. 扩展:进程池

阶段一: 创建多个子进程

阶段二:构建命令方法

ProcessPool.cpp

task.hpp

下一期:进程通信基础知识

结语


一,理解进程之间的通信

首先,系统在设计时,秉持这相互独立的原则,因此要想实现进程之间的通信是比较困难的。而进程之间的通信本质上是:不同的进程能访问同一份数据

1. 进程间通信目的

数据传输:一个进程需要将它的数据发送给另一个进程。
资源共享:多个进程之间共享同样的资源。
通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。实现多进程协同工作,比如:A进程完成,数据收集整合;B进程接受A进程结果,分析问题。

2. 进程间通信的技术背景

1)进程是具有独立性的,虚拟地址 + 页表 保证进程之间的独立性 (内核中数据结构 , 代码以及数据)

2)通信成本比较高。

3,常见的进程间通信

1. Linux系统——管道

2. SystemV——单机通信(多进程)

3. posix——网络通信

二,管道

什么是管道
管道是Unix中最古老的进程间通信的形式。我们把从一个进程连接到另一个进程的一个数据流称为一个“管道。

而这个 “ 管道 ”虽然是一个文件,但它不向硬盘写入,管道里的数据是内存级的临时数据

fd 这个变量就是我们父进程创建的那个pipefile(管道文件描述符存储数组),在经过pipe创建后,将管道的文件描述符填入fd数组中。

1. 尝试建立一个管道

#include <iostream>
#include <unistd.h>
#include <string>
#include <assert.h>
#include <sys/types.h>
using namespace  std;
int main()
{// 用数组记录,读写端int pipefd[2] = {0}; // pipefd[0],是读端,0就如一张口;pipefd[1],是写端,1就如一只笔。int ret = pipe(pipefd);assert(ret != -1);pid_t pd = fork();// 假设父进程需要:写。if (pd == 0){  // 子进程创建成功// 子进程则需要的是:读close(pipefd[1]);cout << "chail success" << endl;char red[1024];// 循环接收并打印数据while (1){read(pipefd[0], red, sizeof (red) -1);cout << red << "### " << "我是子进程,pid:" << getpid() << "父进程: " << getppid() << endl;}exit(1);}// 父进程, 功能:写close(pipefd[0]);string base_str = "我是父进程, 正在给你发消息:";char buffer[1024];   // 输出缓冲区int count = 0;while (1)  // 不断地向子进程发送数据{// 向缓冲区里,不断输入变换的消息int len = snprintf(buffer, sizeof buffer, "%s pid = [%d], 消息数量: %d", base_str.c_str(), getpid(), count++);// 向管道写入write(pipefd[1], buffer, len);sleep(1); // 一秒秒的刷新} return 0;
}

发现现象: 

我们是否注意到,在父进程写数据时,是每隔一秒写一份到管道,而我们没有限制子进程打印的间隔,但从结果来看,向管道内取数据(子进程打印过程)似乎受到了什么控制

我们尝试将父进程写入间隔设置为默认0,将子进程的读出时间设置为10秒一次读。结果上,我们能看到父进程在写入到一定次数后,停止了写入;子进程经过10秒后,会打印一大堆数据,直到打印完为止。从这个现象我们可以发现:

管道提供访问控制。管道本质上也是一个文件,那么也有其最大容量,当即将满时,暂停写入,等待空间当管道为空时,读操作将进行等待,等待数据写入

管道的特点:


1. 管道是用来父子关系的通信管道,是具有继承性的。

2. 管道可以提供进程间通信提供访问控制

3. 管道提供面向流试通信服务(字节流——需要协议进行数据区分,后面我们再聊)。

4. 管道是基于文件的,文件的生命周期是随进程的,因此管道的生命周期也是随进程的。

5. 管道是单向通信,属于半双工通信的一种(半双工意思是永远只有一方在写,一方在读;全双工则可以双方在写,双方在读)

管道提供的访问控制:

2. 扩展:进程池

相关知识:

1.)unin32_t  类型

uint32_t是一个无符号32位整数类型,其意义在于表示一个无符号的32位整数,范围为0到4294967295。使用uint32_t类型可以确保数据的范围和位数符合要求,同时提高代码的可移植性和可读性。这样不管在任何一种型号的机器上sizeof取得的字节数都是4字节。ssize_t类型表示有符号的大小类型,通常用于表示某些系统调用的返回值或参数。它的大小通常与机器的字长相同,即32位机器上为4字节,64位机器上为8字节。ssize_t类型通常用于表示读取或写入的字节数

2.)functiaonal 头文件

头文件 functional 是 C++ 标准库中的一个头文件,它包含了一些模板类函数对象,用于支持函数式编程和泛型编程。这些类和函数对象可以帮助程序员编写更加灵活和抽象的代码,提高代码的可读性和可维护性。它还提供了一些算法和函数,如 std::function、std::bind、std::mem_fn 等,用于处理函数对象和函数指针,以及实现函数的组合、绑定和适配等功能。

因此,头文件 functional 的意义在于为 C++ 程序员提供了一些强大的工具,帮助他们更好地利用函数式编程和泛型编程的特性,提高代码的质量和效率。

首先什么是进程池??

通俗的理解为,子进程替父进程进行数据处理

父进程为了在主程序中完成任务,需要让子进程去处理数据,整理,整合数据,但为了提高创建父进程的效率,在父进程还未向子进程派发任务前,提前创建多个子进程,然后通过管道进行命令传递

阶段一: 创建多个子进程

通过for循环创建多个子进程,并通过管道联系!

阶段二:构建命令方法

我们将方法单独一个文件向管道中读取命令信息,然后根据命令信息调用对应的方法

ProcessPool.cpp

#include <iostream>
#include <assert.h>
#include <vector>
#include <unistd.h>
#include "Task.hpp"    //导入的方法文件
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>using namespace  std;#define NAM_OF_PRO 5// 对命令进行处理
int waitcommand(int fd, bool& quit)
{uint32_t command = 0; // 取个32位的类型,用来获取4字节的数据ssize_t byte = read(fd,  &command,  sizeof command);// 如果父进程没有发送  if (byte == 0)  {quit = true;  // 命令管道开启  //你将他开启了return 0;}// 检测是否是4字节的命令消息1assert(byte == sizeof (uint32_t));return command;
}int main(){ // 阶段一 ; 创建多个子进程// 放pid 与 创建时所在的端口——fdvector<pair<pid_t, int>> slots; // slots 位置的意思 // 创建多个进程for (int i = 0; i < NAM_OF_PRO; i++){// 建立管道int pipefil[2] = {0};int ret = pipe(pipefil);assert(ret != -1); // 管道检测// 创建子进程pid_t fd = fork();if (fd == 0)  // 子进程{// 关闭写端close(pipefil[1]);while (1){   // 处理子进程任务//未接收数据,子进程进入阻塞状态// 阶段二:为子进程设置任务bool quit  = false;   // 管道是否被使用int k = waitcommand(pipefil[0], quit);  // 进入等待命令函数// cout << "K:" << k << " quit " << quit  << endl;if (quit)break;  // 目的:当我们开始关闭管道时,read()会读取0字节,这时让子进程退出tasklist[k]();  // 利用函数容器直接调用,方法函数} exit(1);}// 父进程,关闭读端close(pipefil[0]);// 同时记录子进程,pid数据slots.push_back({fd, pipefil[1]});}// 阶段二: 父进程向子进程传递命令信息// 要想达到子进程接受命令较合理——负载均衡。srand((unsigned)time(0) ^ getpid() * 233333);  // 位运算与相乘2333333,目的是:让数据更随机uint32_t command = 0;Taskloading();  // 对方法进行加载while (true){cout << "###########################################################\n";cout << "##     0. 退出  1. 查看方法表      2. 输入命令  #############\n";cout << "###########################################################\n";cout <<  "请输入:";cin >> command;//你往管道里面写数据的逻辑在哪里,定位到那里先//子进程正常执行了,你的问题是什么    if (command ==  1 ){print_task();// continue;} else if ( command == 2){cout << "Please imput command : ";cin >> command;if (!(command >= 0 && command < tasklist.size())){cout << "无效命令" << endl;continue;}size_t n = rand() % slots.size();  // 随机数选择子进程ssize_t ret = write(slots[n].second, &command, sizeof command);if ( ret != sizeof command){cout << " write  fail " << endl;}else{cout << " write success " << "  child pid:[" << slots[n].first << "] " << "执行:"<< command << " " << task_inf[command]<< endl;}}else if (command == 0){cout << "退出成功" << endl;break;}else{cout << "无效命令,请重新输入" << endl;}sleep(1);}// 完成分配后,关闭管道for (const auto& e : slots){close(e.second);}// 回收子进程for (const auto& e : slots){waitpid(e.first, nullptr, 0); // 由于auto只遍历一次,所以不能用轮询回收}return 0;}

task.hpp

#pragma once
#include <iostream>
#include <assert.h>
#include <vector> 
#include <string>
#include <unordered_map>
#include <functional>
#include <unistd.h>using namespace std;typedef function<void()> func;vector<func> tasklist;   // 记录方法数
unordered_map<int, string> task_inf;  // 记录方法信息。void readMySQL()
{cout << " process : " << getpid() << " 访问数据库";
}void val()
{cout << " process : " << getpid() << " 进行数据运算";
}void save()
{cout << " process : " << getpid() << " 进行数据持久化";
}void cal()
{cout << " process : " << getpid() << " 进行数据加密";
}// 加载任务表
void Taskloading()
{task_inf.insert({tasklist.size(), "readMySQL"});tasklist.push_back(readMySQL);task_inf.insert({tasklist.size(), "val"});tasklist.push_back(val);task_inf.insert({tasklist.size(), "save"});tasklist.push_back(save);task_inf.insert({tasklist.size(), "cal"});tasklist.push_back(cal);cout << "方法加载成功!" << endl;
}// 打印方法表
void print_task()
{for (const auto& e : task_inf){cout << e.first << " " << e.second << endl;}
}int tasksize()
{return tasklist.size();
}

我给大家留了个坑,不知道大家有没有发现呢? 我们在最后的时候调用不了函数

解析: 是进程的独立性导致的。  我们知道我们在已经对方法容器进行了加载,但是在fork之后父进程的加载,父进程进行了实时拷贝,子进程的tasklist任然是未加载状态,这时你就会问了,既然子进程访问的是一个空容器,那我们不就是非法访问了吗?? 是的,我们没有看到报错是因为我们在父进程,子进程的报错不会导致父进程退出,我们通过 查看进程状态表即可发现,由于子进程的非法访问,导致子进程崩溃,成为了僵尸进程

解决方法:

1, fork前,进行方法表加载。

2.   每个子进程都加载。

分析:父子进程,对共享的全局变量,都只是只读的权限,修改则要写实拷贝,因此,要么全局变量在fork之前就数据加载好;要么,在每个子进程都加载一份方法表。如果是我,我会一开始就加载好,这样就只要保存一份数据。

下一期:进程通信基础知识

结语

   本小节就到这里了,感谢小伙伴的浏览,如果有什么建议,欢迎在评论区评论,如果给小伙伴带来一些收获请留下你的小赞,你的点赞和关注将会成为博主创作的动力

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

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

相关文章

synchronized 关键字

目录 1 synchronized 的特性 1&#xff09;互斥 2) 刷新内存&#xff08;内存可见性&#xff09; 3) 可重入 2 synchronized 使用示例 1) 直接修饰普通方法: 2) 修饰静态方法: 3) 修饰代码块: .3 Java 标准库中的线程安全类 1 synchronized 的特性 1&#x…

【Python数据结构与算法】--- 递归算法的应用 ---[乌龟走迷宫] |人工智能|探索扫地机器人工作原理

&#x1f308;个人主页: Aileen_0v0 &#x1f525;系列专栏:PYTHON数据结构与算法学习系列专栏&#x1f4ab;"没有罗马,那就自己创造罗马~" 目录 导言 解决过程 1.建立数据结构 2.探索迷宫: 算法思路 递归调用的“基本结束条件” 3.乌龟走迷宫的实现代码: …

phpstudy和IDEA 配置php debug

1.安装xdebug 扩展&#xff0c;phpinfo() 查看 2.配置php.ini zend_extensionD:/phpstudy_pro/Extensions/php/php7.4.3nts/ext/php_xdebug.dll xdebug.collect_params1 xdebug.collect_return1 xdebug.auto_traceOn xdebug.trace_output_dirD:/phpstudy_pro/Extensions/php_l…

3.OpenResty系列之Nginx反向代理

1. Nginx简介 Nginx (engine x) 是一款轻量级的 Web 服务器 、反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器 什么是反向代理&#xff1f; 反向代理&#xff08;Reverse Proxy&#xff09;方式是指以代理服务器来接受 internet 上的连接请求&#x…

Web安全漏洞分析-XSS(上)

随着互联网的迅猛发展&#xff0c;Web应用的普及程度也愈发广泛。然而&#xff0c;随之而来的是各种安全威胁的不断涌现&#xff0c;其中最为常见而危险的之一就是跨站脚本攻击&#xff08;Cross-Site Scripting&#xff0c;简称XSS&#xff09;。XSS攻击一直以来都是Web安全领…

springboot+vue项目如何集成onlyoffice开源文档组件

一、onlyoffice是什么 ONLYOFFICE 是一个开源的办公套件&#xff0c;适合多人在线协作。由总部位于总部在拉脱维亚的 IT 公司Acensio System SIA 开发。它提供在线协作文档编辑器&#xff08;包括文档、电子表格、演示文稿和表单&#xff09;&#xff0c;适用于 Windows、Linu…

Python with提前退出:坑与解决方案

Python with提前退出&#xff1a;坑与解决方案 问题的起源 早些时候使用with实现了一版全局进程锁&#xff0c;希望实现以下效果&#xff1a; Python with提前退出&#xff1a;坑与解决方案 全局进程锁本身不用多说&#xff0c;大部分都依靠外部的缓存来实现的&#xff0c;r…

进阶C语言-字符函数和字符串函数

字符函数和字符串函数 &#x1f388;1.函数介绍&#x1f50e;1.1strlen函数&#x1f52d;1.1.1strlen函数的模拟实现&#x1f4d6;1.计数器法&#x1f4d6;2.递归法&#x1f4d6;3.指针-指针 &#x1f50e;1.2strcpy函数&#x1f52d;1.2.1strcpy函数的模拟实现 &#x1f50e;1…

【机器学习】算法性能评估常用指标总结

考虑一个二分问题&#xff0c;即将实例分成正类&#xff08;positive&#xff09;或负类&#xff08;negative&#xff09;。对一个二分问题来说&#xff0c;会出现四种情况。如果一个实例是正类并且也被 预测成正类&#xff0c;即为真正类&#xff08;True positive&#xff0…

1.前端--基本概念【2023.11.25】

1.网站与网页 网站是网页集合。 网页是网站中的一“页”&#xff0c;通常是 HTML 格式的文件&#xff0c;它要通过浏览器来阅读。 2.Web的构成 主要包括结构&#xff08;Structure&#xff09; 、表现&#xff08;Presentation&#xff09;和行为&#xff08;Behavior&#xff…

【深度学习】DAMO-YOLO,阿里,701类通用检测模型,目标检测

https://github.com/tinyvision/DAMO-YOLO/blob/master/README_cn.md DAMO-YOLO是由阿里巴巴达摩院智能计算实验室TinyML团队开发的一个兼顾速度与精度的目标检测框架,其效果超越了目前的一众YOLO系列方法&#xff0c;在实现SOTA的同时&#xff0c;保持了很高的推理速度。DAMO…

虚幻学习笔记4—文本内容处理

一、前言 本文使用的虚幻引擎5.3.2&#xff0c;在虚幻中已经集成了很多可以直接处理多样化文本的蓝图&#xff0c;比如格式化动态显示、浮点数多样化等。 二、实现 2.1、格式化文本显示动态内容&#xff1a;在设置某个文本时可以使用“Format Text”蓝图设置自定义可以的显示…

继承中的析构函数的权限的深入了解

如果一个父类中的析构函数如果设置为 private 权限 &#xff0c;一个子类public继承了这个父类&#xff0c;那么 这个父类可以创建对象吗&#xff1f; 答案是 不可以 看看下面的代码 class A { public:private:~A() {} };class B :public A {A a; // 这个地方编译不报错&…

数据结构——带头循环双向链表(List)

1、带头双向循环链表介绍 在上一篇博客中我们提到了链表有三个特性&#xff0c;可以组合成为8种不同类型的链表。单链表是其中比较重要的一种&#xff0c;那么这次我们选择和带头双向循环链表会会面&#xff0c;这样我们就见识过了所有三种特性的呈现。 带头双向循环链表&#…

基于C#实现优先队列

一、堆结构 1.1性质 堆是一种很松散的序结构树&#xff0c;只保存了父节点和孩子节点的大小关系&#xff0c;并不规定左右孩子的大小&#xff0c;不像排序树那样严格&#xff0c;又因为堆是一种完全二叉树&#xff0c;设节点为 i,则 i/2 是 i 的父节点&#xff0c;2i 是 i 的…

Pytorch 基于 deeplabv3_resnet50 迁移训练自己的图像语义分割模型

一、图像语义分割 图像语义分割是计算机视觉领域的一项重要任务&#xff0c;旨在将图像中的每个像素分配到其所属的语义类别&#xff0c;从而实现对图像内容的细粒度理解。与目标检测不同&#xff0c;图像语义分割要求对图像中的每个像素进行分类&#xff0c;而不仅仅是确定物…

图形数据库的实战应用:如何在 Neo4j 中有效管理复杂关系

关系数据库管理系统( RDBMS ) 代表了最先进的技术&#xff0c;这在一定程度上要归功于其由周边技术、工具和广泛的专业技能组成的完善的生态系统。 在这个涵盖信息技术(IT) 和运营技术(OT) 的技术革命时代&#xff0c;人们普遍认识到性能方面出现了重大挑战&#xff0c;特别是…

【广州华锐互动】Web3D云展编辑器能为展览行业带来哪些便利?

在数字时代中&#xff0c;传统的展览方式正在被全新的技术和工具所颠覆。其中&#xff0c;最具有革新意义的就是Web3D云展编辑器。这种编辑器以其强大的功能和灵活的应用&#xff0c;正在为展览设计带来革命性的变化。 广州华锐互动开发的Web3D云展编辑器是一种专门用于创建、编…

关于网站的favicon.ico图标的设置需要注意的几点

01-必须在网页的head标签中放上对icon图标的说明语句&#xff1a; 比如下面这样的语句&#xff1a; <link rel"shortcut icon" href"/favicon.ico">否则&#xff0c;浏览器虽然能读到图标&#xff0c;但是不会把图标显示在标签上。 02-为了和本地开…

DHCP、ARP、FTP、DNS、VRRP、STP、报文交互流程

目录 一、DHCP 1、DHCP终结 1、DHCP discover 2、DHCP offer 3、DHCP request 4、DHCP ack 5、DHCP request 6、DHCP 续租 2、DHCP终结 二、ARP 1、ARP类型 动态ARP 静态ARP ARP代理 ARP代理的分类&#xff1a;路由式代理、VLAN内的ARP代理、VLAN间的ARP代理。 6…