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

Linux - 进程间通信(3)

目录

3、解决遗留BUG -- 边关闭信道边回收进程

1)解决方案

2)两种方法相比较

4、命名管道

1)理解命名管道

2)创建命名管道

a. 命令行指令

b. 系统调用方法

3)代码实现命名管道

构建类进行封装命名管道:

构造和析构:

读取管道、写入管道:

server.cc (读端):

client.cc(写端):

效果:

4)疑点解决

写端未来,读端open调用阻塞

读端关闭,写端继续写入

5)完整代码

namedPipe.hpp:

server.cc:

client.cc:


3、解决遗留BUG -- 边关闭信道边回收进程

1)解决方案

我们仍然想用上述方法进行管道和子进程的回收

-- 则需要解决子进程所继承的父进程遗留的多余wfd,我们在每次创建子进程时,遍历所有之前的信道,关闭掉wfd即可,就不会出现,多个wfd指向一个管道

2)两种方法相比较

退一个回收一个:

先全部退出,再进行等待回收:

4、命名管道

1)理解命名管道

命名:该管道有名字,因为该文件有路径,有路径必有文件名

管道:依旧是一个内存级的基于文件进行通信的通信方案

属性、操作、文件内核缓冲区同一个文件的都是差不多的,因此不用再创建一份,操作系统不做浪费时间和空间的事情

我们怎么保证两个毫不相关的进程打开了同一个文件呢??
每一个文件,都有文件路径(唯一性)

2)创建命名管道

a. 命令行指令

一个进程(echo)向命名管道里面输入数据

一个进程(cat)向命名管道里面读取数据

这样就实现了两个毫不相关的进行之间的通信

创建了三个窗口,一个一直向管道输入,一个一直读取,一个手动检测管道大小

但是我们可以看到管道文件(myfifo)的大小一直显示0

因为 FIFO0 文件虽存在于文件系统中,但其内容都存放在内存里,不会将通信数据刷新到磁盘中,所以在磁盘上显示的文件大小始终为0

b. 系统调用方法

使用mkfifo即可创建管道文件

使用unlink即可删除一个管道文件(当然,rm也可以删除)

3)代码实现命名管道

创建两个.cc文件分别模拟两个进程,一个进行发送,一个进行读取

通过一个CreateNamedPipe和一个RemoveNamedPipe就可以实现对管道生命周期的管理

当然,我们管理管道的声明周期时,肯定是将创建和删除交给同一个文件去做比较好,因为它清楚什么时候去删除合适

这里我们让发送的那方去管理管道的生命周期

构建类进行封装命名管道:

我们需要创建管道的路径(共同路径)、创建管道的身份、管道的文件描述符

class NamedPipe
{
private:const std::string _fifo_path;int _id;int _fd;
};
构造和析构:
class NamedPipe
{
public:NamedPipe(const std::string &path, int who): _fifo_path(path), _id(who), _fd(DefaultFd){if (_id == Creater){int res = mkfifo(_fifo_path.c_str(), 0666);if (res != 0){perror("mkfifo");}std::cout << "creater create named pipe" << std::endl;}}~NamedPipe(){sleep(5);if (_id == Creater){int res = unlink(_fifo_path.c_str());if (res != 0){perror("unlink");}std::cout << "creater remove named pipe" << std::endl;}if(_fd != DefaultFd) close(_fd);}private:const std::string _fifo_path;int _id;int _fd;
};
读取管道、写入管道:
class NamedPipe
{
private:bool OpenNamedPipe(int mode){_fd = open(_fifo_path.c_str(), mode);if(_fd < 0) return false;return true;}public:NamedPipe(const std::string &path, int who): _fifo_path(path), _id(who), _fd(DefaultFd){if (_id == Creater){int res = mkfifo(_fifo_path.c_str(), 0666);if (res != 0){perror("mkfifo");}std::cout << "creater create named pipe" << std::endl;}}bool OpenForRead(){return OpenNamedPipe(Read);}bool OpenForWrite(){return OpenNamedPipe(Write);}int ReadNamedPipe(std::string *out){char buffer[BaseSize];int n = read(_fd, buffer, sizeof(buffer));if(n > 0){buffer[n] = 0; // '\0'*out = buffer;}return n;}int WriteNamedPipe(const std::string &in){return write(_fd, in.c_str(), in.size());}~NamedPipe(){sleep(5);if (_id == Creater){int res = unlink(_fifo_path.c_str());if (res != 0){perror("unlink");}std::cout << "creater remove named pipe" << std::endl;}if(_fd != DefaultFd) close(_fd);}private:const std::string _fifo_path;int _id;int _fd;
};
server.cc (读端):
#include "namedPipe.hpp"// server -- read : 管理命名管道的整个生命周期
int main()
{NamedPipe fifo(comm_path, Creater);// 对于读端而言,如果我们打开了文件,但是写还没有来,我们会阻塞在open调中,直到对方打开// --> 一种变向的进程同步if (fifo.OpenForRead()){std::cout << "Server open named pipe done" << std::endl; // 为了检测阻塞sleep(3);while (true){std::string message;int n = fifo.ReadNamedPipe(&message);if (n > 0) // 正常接收{std::cout << "Client Say > " << message << std::endl;}else if(n == 0) // 即写端关闭{std::cout << "Client quit, Server too!" << std::endl;break;}else {std::cout << "fifo.ReadNamedPipe Error!" << std::endl;break;}}}return 0;
}
client.cc(写端):
#include "namedPipe.hpp"// client -- write
int main()
{NamedPipe fifo(comm_path, User); // 以非创建身份实例化if(fifo.OpenForWrite()){std::cout << "client open named pipe done" << std::endl;while(true){std::cout << "Please Enter > ";std::string message;std::getline(std::cin, message);fifo.WriteNamedPipe(message);}}return 0;
}
效果:

实现了两个进程(无父子关系)之间的通信

4)疑点解决

写端未来,读端open调用阻塞

读端关闭,写端继续写入

5)完整代码

namedPipe.hpp:
#pragma once#include <iostream>
#include <string>
#include <cstdio>
#include <cerrno>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>const std::string comm_path = "./myfifo";#define DefaultFd -1
#define Creater 1
#define User 2
#define Read O_RDONLY
#define Write O_WRONLY
#define BaseSize 4096class NamedPipe
{
private:bool OpenNamedPipe(int mode){_fd = open(_fifo_path.c_str(), mode);if(_fd < 0) return false;return true;}public:NamedPipe(const std::string &path, int who): _fifo_path(path), _id(who), _fd(DefaultFd){if (_id == Creater){int res = mkfifo(_fifo_path.c_str(), 0666);if (res != 0){perror("mkfifo");}std::cout << "creater create named pipe" << std::endl;}}bool OpenForRead(){return OpenNamedPipe(Read);}bool OpenForWrite(){return OpenNamedPipe(Write);}int ReadNamedPipe(std::string *out){char buffer[BaseSize];int n = read(_fd, buffer, sizeof(buffer));if(n > 0){buffer[n] = 0; // '\0'*out = buffer;}return n;}int WriteNamedPipe(const std::string &in){return write(_fd, in.c_str(), in.size());}~NamedPipe(){sleep(5);if (_id == Creater){int res = unlink(_fifo_path.c_str());if (res != 0){perror("unlink");}std::cout << "creater remove named pipe" << std::endl;}if(_fd != DefaultFd) close(_fd);}private:const std::string _fifo_path;int _id;int _fd;
};
server.cc:
#include "namedPipe.hpp"// server -- read : 管理命名管道的整个生命周期
int main()
{NamedPipe fifo(comm_path, Creater);// 对于读端而言,如果我们打开了文件,但是写还没有来,我们会阻塞在open调中,直到对方打开// --> 一种变向的进程同步if (fifo.OpenForRead()){std::cout << "Server open named pipe done" << std::endl;sleep(3);while (true){std::string message;int n = fifo.ReadNamedPipe(&message);if (n > 0){std::cout << "Client Say > " << message << std::endl;}else if(n == 0){std::cout << "Client quit, Server too!" << std::endl;break;}else{std::cout << "fifo.ReadNamedPipe Error!" << std::endl;break;}}}return 0;
}
client.cc:
#include "namedPipe.hpp"// client -- write
int main()
{NamedPipe fifo(comm_path, User);if(fifo.OpenForWrite()){std::cout << "client open named pipe done" << std::endl;while(true){std::cout << "Please Enter > ";std::string message;std::getline(std::cin, message);fifo.WriteNamedPipe(message);}}return 0;
}

相关文章:

Linux - 进程间通信(3)

目录 3、解决遗留BUG -- 边关闭信道边回收进程 1&#xff09;解决方案 2&#xff09;两种方法相比较 4、命名管道 1&#xff09;理解命名管道 2&#xff09;创建命名管道 a. 命令行指令 b. 系统调用方法 3&#xff09;代码实现命名管道 构建类进行封装命名管道&#…...

3、C#基于.net framework的应用开发实战编程 - 实现(三、三) - 编程手把手系列文章...

三、 实现&#xff1b; 三&#xff0e;三、编写应用程序&#xff1b; 此文主要是实现应用的主要编码工作。 1、 分层&#xff1b; 此例子主要分为UI、Helper、DAL等层。UI负责便签的界面显示&#xff1b;Helper主要是链接UI和数据库操作的中间层&#xff1b;DAL为对数据库的操…...

C++编程语言:抽象机制:泛型编程(Bjarne Stroustrup)

泛型编程(Generic Programming) 目录 24.1 引言(Introduction) 24.2 算法和(通用性的)提升(Algorithms and Lifting) 24.3 概念(此指模板参数的插件)(Concepts) 24.3.1 发现插件集(Discovering a Concept) 24.3.2 概念与约束(Concepts and Constraints) 24.4 具体化…...

Python面试宝典13 | Python 变量作用域,从入门到精通

今天&#xff0c;我们来深入探讨一下 Python 中一个非常重要的概念——变量作用域。理解变量作用域对于编写清晰、可维护、无 bug 的代码至关重要。 什么是变量作用域&#xff1f; 简单来说&#xff0c;变量作用域就是指一个变量在程序中可以被访问的范围。Python 中有四种作…...

基于最近邻数据进行分类

人工智能例子汇总&#xff1a;AI常见的算法和例子-CSDN博客 完整代码&#xff1a; import torch import numpy as np from sklearn.neighbors import KNeighborsClassifier from sklearn.metrics import accuracy_score import matplotlib.pyplot as plt# 生成一个简单的数据…...

DeepSeek V3 vs R1:大模型技术路径的“瑞士军刀“与“手术刀“进化

DeepSeek V3 vs R1&#xff1a;——大模型技术路径的"瑞士军刀"与"手术刀"进化 大模型分水岭&#xff1a;从通用智能到垂直突破 2023年&#xff0c;GPT-4 Turbo的发布标志着通用大模型进入性能瓶颈期。当模型参数量突破万亿级门槛后&#xff0c;研究者们开…...

一、TensorFlow的建模流程

1. 数据准备与预处理&#xff1a; 加载数据&#xff1a;使用内置数据集或自定义数据。 预处理&#xff1a;归一化、调整维度、数据增强。 划分数据集&#xff1a;训练集、验证集、测试集。 转换为Dataset对象&#xff1a;利用tf.data优化数据流水线。 import tensorflow a…...

指导初学者使用Anaconda运行GitHub上One - DM项目的步骤

以下是指导初学者使用Anaconda运行GitHub上One - DM项目的步骤&#xff1a; 1. 安装Anaconda 下载Anaconda&#xff1a; 让初学者访问Anaconda官网&#xff08;https://www.anaconda.com/products/distribution&#xff09;&#xff0c;根据其操作系统&#xff08;Windows、M…...

7层还是4层?网络模型又为什么要分层?

~犬&#x1f4f0;余~ “我欲贱而贵&#xff0c;愚而智&#xff0c;贫而富&#xff0c;可乎&#xff1f; 曰&#xff1a;其唯学乎” 一、为什么要分层 \quad 网络通信的复杂性促使我们需要一种分层的方法来理解和管理网络。就像建筑一样&#xff0c;我们不会把所有功能都混在一起…...

C++:抽象类习题

题目内容&#xff1a; 求正方体、球、圆柱的表面积&#xff0c;抽象出一个公共的基类Container为抽象类&#xff0c;在其中定义一个公共的数据成员radius(此数据可以作为正方形的边长、球的半径、圆柱体底面圆半径)&#xff0c;以及求表面积的纯虚函数area()。由此抽象类派生出…...

C++ 泛型编程指南02 (模板参数的类型推导)

文章目录 一 深入了解C中的函数模板类型推断什么是类型推断&#xff1f;使用Boost TypeIndex库进行类型推断分析示例代码关键点解析 2. 理解函数模板类型推断2.1 指针或引用类型2.1.1 忽略引用2.1.2 保持const属性2.1.3 处理指针类型 2.2 万能引用类型2.3 传值方式2.4 传值方式…...

音视频入门基础:RTP专题(5)——FFmpeg源码中,解析SDP的实现

一、引言 FFmpeg源码中通过ff_sdp_parse函数解析SDP。该函数定义在libavformat/rtsp.c中&#xff1a; int ff_sdp_parse(AVFormatContext *s, const char *content) {const char *p;int letter, i;char buf[SDP_MAX_SIZE], *q;SDPParseState sdp_parse_state { { 0 } }, *s1…...

计算机网络 应用层 笔记 (电子邮件系统,SMTP,POP3,MIME,IMAP,万维网,HTTP,html)

电子邮件系统&#xff1a; SMTP协议 基本概念 工作原理 连接建立&#xff1a; 命令交互 客户端发送命令&#xff1a; 服务器响应&#xff1a; 邮件传输&#xff1a; 连接关闭&#xff1a; 主要命令 邮件发送流程 SMTP的缺点: MIME&#xff1a; POP3协议 基本概念…...

【视频+图文详解】HTML基础3-html常用标签

图文教程 html常用标签 常用标签 1. 文档结构 <!DOCTYPE html>&#xff1a;声明HTML文档类型。<html>&#xff1a;定义HTML文档的根元素。<head>&#xff1a;定义文档头部&#xff0c;包含元数据。<title>&#xff1a;设置网页标题&#xff0c;浏览…...

FreeRTOS学习 --- 消息队列

队列简介 队列是任务到任务、任务到中断、中断到任务数据交流的一种机制&#xff08;消息传递&#xff09; 全局变量的弊端&#xff1a;数据无保护&#xff0c;导致数据不安全&#xff0c;当多个任务同时对该变量操作时&#xff0c;数据易受损 使用队列的情况如下&#xff1a;…...

PHP If...Else 语句详解

PHP If...Else 语句详解 引言 在PHP编程中&#xff0c;if...else语句是流程控制的重要组成部分&#xff0c;它允许程序根据条件判断执行不同的代码块。本文将详细解析PHP中的if...else语句&#xff0c;包括其基本用法、高级技巧以及注意事项。 一、基本用法 if...else语句的…...

pytorch使用SVM实现文本分类

人工智能例子汇总&#xff1a;AI常见的算法和例子-CSDN博客 完整代码&#xff1a; import torch import torch.nn as nn import torch.optim as optim import jieba import numpy as np from sklearn.model_selection import train_test_split from sklearn.feature_extract…...

安卓(android)读取手机通讯录【Android移动开发基础案例教程(第2版)黑马程序员】

一、实验目的&#xff08;如果代码有错漏&#xff0c;可在代码地址查看&#xff09; 1.熟悉内容提供者(Content Provider)的概念和作用。 2.掌握内容提供者的创建和使用方法。 4.掌握内容URI的结构和用途。 二、实验条件 1.熟悉内容提供者的工作原理。 2.掌握内容提供者访问其…...

【Qt】常用的容器

Qt提供了多个基于模板的容器类&#xff0c;这些容器类可用于存储指定类型的数据项。例如常用的字符串列表类 QStringList 可用来操作一个 QList<QString>列表。 Qt的容器类比标准模板库(standard template library&#xff0c;STL)中的容器类更轻巧、使用更安全且更易于使…...

基于UKF-IMM无迹卡尔曼滤波与交互式多模型的轨迹跟踪算法matlab仿真,对比EKF-IMM和UKF

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于UKF-IMM无迹卡尔曼滤波与交互式多模型的轨迹跟踪算法matlab仿真,对比EKF-IMM和UKF。 2.测试软件版本以及运行结果展示 MATLAB2022A版本运行 3.核心程序 .…...

别再乱装CUDA了!保姆级教程:从显卡驱动到PyTorch 2.x,一次搞定Windows深度学习环境

深度学习环境配置避坑指南&#xff1a;从显卡驱动到PyTorch 2.x全流程解析 刚接触深度学习的开发者&#xff0c;往往在环境配置阶段就遭遇重重阻碍。显卡驱动与CUDA版本不匹配、cuDNN安装失败、PyTorch下载缓慢等问题&#xff0c;让许多初学者在起步阶段就耗费大量时间。本文将…...

03 MongoDB文档的各种增加、更新、删除操作总结

更多内容请见: 《深入掌握MongoDB数据库》 - 专栏介绍和目录 一. 插入文档 注意: 在 MongoDB 中,直接插入内容会自动创建集合! 1.1 使用insert()方法 语法格式: db.COLLECTION_NAME.insert(document) 说明: 若插入的数据主键已经存在,则会抛 org.springframework.dao.Du…...

避开这3个坑,你的软考数据库设计题至少多拿10分:从E-R图合并冲突到SQL约束实战

软考数据库设计题避坑指南&#xff1a;从E-R图到SQL约束的实战技巧 每次软考结束&#xff0c;总有一批考生捶胸顿足——"那道数据库设计题明明会做&#xff0c;怎么又丢分了&#xff1f;"作为参加过三次软考阅卷的数据库讲师&#xff0c;我发现90%的失分都集中在几个…...

从零开始:roLabelImg安装与OBB旋转框标注实战指南

1. 为什么需要roLabelImg和旋转框标注 在计算机视觉项目中&#xff0c;我们经常需要标注图像中的目标物体。对于常规的矩形框标注&#xff0c;LabelImg这类工具已经足够好用。但遇到倾斜物体时&#xff0c;比如遥感图像中的飞机、自然场景中的交通标志、医学图像中的器官&#…...

PyTorch模型转ONNX避坑指南:从repeat_interleave到Concat类型匹配的实战解决方案

PyTorch模型转ONNX避坑指南&#xff1a;从动态张量到类型匹配的深度解决方案 在模型部署的最后一公里&#xff0c;PyTorch到ONNX的转换常常成为绊倒开发者的隐蔽陷阱。当你在本地训练环境获得完美指标后&#xff0c;准备将模型推向生产时&#xff0c;各种意想不到的导出错误可能…...

NVIDIA Profile Inspector实战手册:从参数调试到显卡性能全面优化

NVIDIA Profile Inspector实战手册&#xff1a;从参数调试到显卡性能全面优化 【免费下载链接】nvidiaProfileInspector 项目地址: https://gitcode.com/gh_mirrors/nv/nvidiaProfileInspector 在PC硬件优化领域&#xff0c;专业工具与普通用户之间往往存在技术鸿沟。N…...

信创协同办公价格与成本:这样选,性价比直接拉满!

“一套信创协同办公到底多少钱&#xff1f;”“是按人头收费&#xff0c;还是按项目打包算&#xff1f;”“前期买着便宜&#xff0c;后期维护会不会无底洞&#xff1f;”不管是政企单位采购&#xff0c;还是企业选型&#xff0c;这三个问题几乎是所有人的核心顾虑。毕竟信创办…...

从‘硬’开关到‘软’启动:拆解一个经典PMOS缓启动电路,聊聊D4、D6这些二极管到底在忙啥?

从‘硬’开关到‘软’启动&#xff1a;拆解一个经典PMOS缓启动电路&#xff0c;聊聊D4、D6这些二极管到底在忙啥&#xff1f; 在硬件设计中&#xff0c;电源管理电路如同交响乐团的指挥&#xff0c;协调着各个器件的动作节奏。而缓启动电路&#xff0c;则是这位指挥手中那根至关…...

Ubuntu 虚拟机 Python3 + pip 完整安装教程

文章目录一、先检查系统是否自带 Python3二、安装 Python3 和 pip&#xff08;必装&#xff09;1. 更新软件源2. 安装 python3 和 pip3. 验证安装成功三、最简单的使用方法1. 运行 Python2. 用 pip 安装第三方库&#xff08;如 requests、numpy&#xff09;3. 运行 .py 文件四、…...

PySide6新手必看:从零开始用Python玩转Qt界面开发(附官方教程对比)

PySide6新手必看&#xff1a;从零开始用Python玩转Qt界面开发 在Python生态中&#xff0c;GUI开发一直是个让人又爱又恨的话题。当Tkinter显得过于简陋&#xff0c;而PyQt又面临商业授权困扰时&#xff0c;PySide6作为Qt官方推出的Python绑定&#xff0c;正成为越来越多开发者的…...