【Linux操作系统】进程间通信(1)

news2024/11/14 21:50:50

目录

  • 一、认识进程间通信
  • 二、匿名管道
  • 三、命名管道

一、认识进程间通信

进程间不能直接传递数据,因为进程具有独立性,直接传递会破坏进程的独立性。

进程间通信是什么?

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

为什么要有进程间通信?

需要多个进程协同,共同完成一些事(数据共享、资源共享、通知事件、进程控制)

怎么做?

先让不同的进程看到同一份资源,这个同一份资源由操作系统提供。交换数据的内存,不能由通信双方的任何一个提供。

具体:因为操作系统提供空间有不同的方式,所以有不同的通信方式——管道、共享内存、消息队列、信号量

二、匿名管道

一个进程的PCB对象里面有指向files_struct类型结构体的指针,该结构体里面有文件描述符表,0-2分别指向的是系统默认打开的标准输入、标准输出和标准错误。当往一个文件(磁盘中的log.txt)写入数据,然后读取数据,共两次操作,struct file会有两个,一个是写的,另一个是读的(不同指针指向同一个文件)。w操作调用系统接口,将写入的数据给缓冲区,然后再刷新到磁盘的文件中;r操作,磁盘的文件的数据先到缓冲区,然后对应的系统接口再把数据读取出来。总之,写入和读取都是在缓冲区进行的,因为缓冲区也是内存,调用系统接口,就是运行某个程序,程序和磁盘中文件要加载到内存。如果让当前进程fork后创建一个子进程,那么子进程的文件描述符表里面的下标3和4也指向父进程指向的struct file,files_struct是进程的属性之一,所以创建子进程时子进程的PCB对象也有files_struct,而struct file是文件系统的,就一份。因此,此时的父子进程如图指向struct file的w文件和r文件,w和r指向同一个内存缓冲区,然后再到磁盘中的一个文件log.txt。
在这里插入图片描述
既然有创建子进程,就是要子进程办事的,如果让子进程w,父进程r,那么,子进程写的通过缓冲区刷新到磁盘文件中(写的时候,文件要先被加载到内存,即缓冲区,),然后,父进程通过缓冲区读取文件的信息(也是在缓冲区,即内存中。不管读写,都要先将文件加载到内存执行)。这样,子进程写的,父进程就能看到,所以,在这里父子进程通过缓冲区,即一块内存,就能够看到同一份资源的,这种方式或者说是通信方式就叫管道。

管道只能是单向通信。父进程最开始时的权限是rw,因为这样给子进程也是rw,然后关闭权限(父进程关闭w,子进程关闭r,注意,父进程刚开始不能只有一个r或w,因为不能新打开权限),一个读,一个写。

为了实现管道通信,OS提供了系统调用pipe() 。pipefd数组得到两个fd,分别是读r和写w(输出型参数)
在这里插入图片描述
特点:不需要向磁盘刷新内容,它不是一个文件,磁盘中也不存在这个文件。也就是说它会有一块内存,但是与磁盘无关,它是一个内存级文件,没有名字,是匿名的,一般就叫它——管道。

匿名管道如何让不同的进程看到同一份资源?创建子进程,子进程继承父进程相关的属性信息。只能具有“血缘”关系的进程可以进程间通信,常用于父子进程。

代码:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/wait.h>

void reader(int rfd)
{
    char buffer[1024];
    while(1)
    {
        ssize_t n = read(rfd, buffer, sizeof(buffer));
        printf("message: %s\n", buffer);
        sleep(1);
    }
}
void writer(int wfd)
{
    char* str = "I am father";
    char buf[1024];
    int cnt = 1;
    pid_t pid = getpid();
    while(1)
    {
        snprintf(buf, sizeof(buf), "message: %s, pid: %d, cnt: %d", str, pid, cnt);
        write(wfd, buf, sizeof(buf));
        cnt++;
        sleep(1);
    }
}
int main()
{
    //1、创建管道
    int pipefd[2];
    int n = pipe(pipefd);
    if(n < 0) return 1;

    //2、创建子进程
    pid_t id = fork();
    if(id == 0)
    {
        //子进程读
        close(pipefd[1]);//关闭写
        reader(pipefd[0]);//读
        exit(0);
    }
    //父进程写
    close(pipefd[0]);//关闭读
    writer(pipefd[1]);//写
    wait(NULL);//防止僵尸
    return 0;
}

在这里插入图片描述
4种情况:一、管道内部没有数据,并且写端没有关闭,那么读端就要阻塞等待,直到pipe有数据;二、管道内部被写满,并且读端不关闭,那么写端写满之后,就要阻塞等待;三、对于写端,不写了,并且管道关闭,那么读端会把管道内的所有数据读完,最后读到返回值为0,表示读结束;四、读端不读并且关闭,写端在写,那么操作系统就会直接终止写入的进程

5种特性:一、自带同步机制(管道内部有数据,读端就读,没有就等待;管道没有写满,写端就写,满了就等待);二、血缘关系进程间通信,常见于父子进程;三、pipe是面向字节流的(写可能是一个一个的写,但是读可以一次性全部读出来);四、父子进程退出,管道自动释放,文件的生命周期是随进程的;五、管道只能单向通信。

命令行管道| 本质是匿名管道

三、命名管道

两个特点:1、让不同进程看到同一份资源;2、让没有亲缘关系的进程可以进行通信
在这里插入图片描述

怎么保证两个不同的进程打开的是同一个文件?找到文件:文件名+文件路径

系统调用接口:mkfifo、unlink
在这里插入图片描述
在这里插入图片描述

验证代码:
两个不相干的进程,一个发送消息,另一个接收

Comm.hpp

#ifndef __COMM_HPP__
#define __COMM_HPP__

#include <iostream>
#include <unistd.h>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <cstdlib>
#include <fcntl.h>

using namespace std;
#define Mode 0666
#define Path "fifo"

class Fifo
{
public:
    Fifo(const string &path) : _path(path)
    {
        umask(0);
        //创建管道
        int n = mkfifo(_path.c_str(), Mode);
        if(n == 0)
        {
            cout << "fifo create success" <<endl;
        }
        else 
        {
            cout << "fifo fail, errno: " << errno << " stringerrno: " << strerror(errno) << endl;
        }
    }
    ~Fifo()
    {
        //删除管道,管道也是文件
        int n = unlink(_path.c_str());
        if(n == 0)
        {
            cout << "fifo remove success" <<endl;
        }
        else 
        {
            cout << "fifo remove, errno: " << errno << " stringerrno: " << strerror(errno) << endl;
        }
    }

private:
    string _path;//文件名+文件路径
};

#endif

pipeServer.cc

#include "Comm.hpp"

int main()
{
    Fifo fifo(Path);//实例化
    //打开文件
    int rfd = open(Path, O_RDONLY);
    if(rfd < 0)
    {
        cout << "open fail, errno: " << errno << " stringerrno: " << strerror(errno) << endl;
        return 1;
    }
    char buffer[1024];
    while(true)
    {
        ssize_t n = read(rfd, buffer, sizeof(buffer)-1);
        if(n > 0)//读取成功
        {
            buffer[n] = 0;
            cout << "message: " <<buffer<<endl;
        }
        else if(n == 0)//读停止 
        {
            cout << "read quit.. " <<endl;
            break;
        }
        else //读失败
        {
            cout << "read fail, errno: " << errno << " stringerrno: " << strerror(errno) << endl;
            break;
        }
    }
    close(rfd);//关闭文件
    return 0;
}

pipeClient.cc

#include "Comm.hpp"

int main()
{
    //打开文件
    int wfd = open(Path, O_WRONLY);
    if(wfd < 0)
    {
        cout << "open fail, errno: " << errno << " stringerrno: " << strerror(errno) << endl;
        return 1;
    }
    string buffer;
    while(true)
    {
        cout << "Please message# ";
        getline(cin, buffer);
        ssize_t n = write(wfd, buffer.c_str(), buffer.size());
        if(n < 0)
        {
            cout << "write fail, errno: " << errno << " stringerrno: " << strerror(errno) << endl;
            break;
        }
    }

    close(wfd);//关闭文件
    return 0;
}

在这里插入图片描述

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

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

相关文章

ThreadLocal解惑

目录 1、ThreadLocal是什么? 2、ThreadLocal实现原理 3、设置线程变量的2种方式 4、关于ThreadLocal的内存泄漏问题 5、使用过程中的注意事项和误区 1、ThreadLocal是什么? 比较书面的回答&#xff1a; 类如其名&#xff0c;线程本地变量。当使用 ThreadLocal 维护变量时…

防爆巡检机器人:工业安全领域的璀璨明星

在当今快速发展的工业领域&#xff0c;安全与效率是企业追求的双核动力。特别是在石油、化工、钢铁冶金、燃气等高风险、高爆炸性的行业中&#xff0c;如何确保生产环境的绝对安全&#xff0c;同时提升巡检效率&#xff0c;成为了企业亟需解决的重大课题。正是在这样的背景下&a…

leetcode 438 找到字符串中所有字母异位词

leetcode 438 找到字符串中所有字母异位词 正文 正文 本题和 leetcode 49 字母异位分词 有些类似&#xff0c;只是 49 题中要求我们找出所有的异位词并进行存储&#xff0c;而本题我们只需要找出异位词对应的索引值。因此&#xff0c;我们无需用到字典&#xff0c;只需使用列表…

理解线程 ID 和 LWP

序言 在不同的系统中&#xff0c;为了更好地管理用户可能会采取不同的编号。比如在学校的教务系统中&#xff0c;管理学生使用的是学号&#xff1b;但是在住宿系统中&#xff0c;为了更加方便的获取一个学生的寝室信息&#xff0c;可能会采取结合你是哪一栋&#xff0c;哪一层&…

MindSearch 部署的到 Hugging Face Space

和原有的CPU版本相比区别是把internstudio换成了github codespace。 随着硅基流动提供了免费的 InternLM2.5-7B-Chat 服务&#xff08;免费的 InternLM2.5-7B-Chat 真的很香&#xff09;&#xff0c;MindSearch 的部署与使用也就迎来了纯 CPU 版本&#xff0c;进一步降低了部署…

【Windows】深度学习环境部署

引言 1 Windows环境准备 1.1 VSCode Visual Studio Code&#xff08;简称 VSCode&#xff09;是一款由微软开发的开源代码编辑器。它非常受开发者欢迎&#xff0c;因为它功能强大、扩展性好&#xff0c;并且支持多种编程语言。VSCode 尤其适合 Python 开发&#xff0c;特别是…

WEB渗透免杀篇-Pezor免杀

往期文章 WEB渗透免杀篇-免杀工具全集-CSDN博客 WEB渗透免杀篇-加载器免杀-CSDN博客 WEB渗透免杀篇-分块免杀-CSDN博客 WEB渗透免杀篇-Powershell免杀-CSDN博客 WEB渗透免杀篇-Python源码免杀-CSDN博客 WEB渗透免杀篇-C#源码免杀-CSDN博客 WEB渗透免杀篇-MSFshellcode免杀…

文心一言 VS 讯飞星火 VS chatgpt (331)-- 算法导论22.5 7题

七、给定有向图 G ( V &#xff0c; E ) G(V&#xff0c;E) G(V&#xff0c;E)&#xff0c;如果对于所有结点对 u , v ∈ V u,v∈V u,v∈V,我们有 u → v u→v u→v或 v → u v→u v→u&#xff0c;则 G G G是半连通的。请给出一个有效的算法来判断图 G G G是否是半连通的。证…

根据需求、质量属性描述和架构特性开发一套公路桥梁在线管理系统

目录 案例 【题目】 【问题 1】(12 分) 【问题 2】(13 分) 答案 【问题 1】答案 【问题 2】答案 相关推荐 案例 阅读以下关于软件架构评估的叙述&#xff0c;在答题纸上回答问题 1 和问题 2。 【题目】 某单位为了建设健全的公路桥梁养护管理档案&#xff0c;拟开发一套公…

若依框架搭建

一、后端启动 1、git克隆下载前后端分离版本 RuoYi-Vue: &#x1f389; 基于SpringBoot&#xff0c;Spring Security&#xff0c;JWT&#xff0c;Vue & Element 的前后端分离权限管理系统&#xff0c;同时提供了 Vue3 的版本 (gitee.com) 2、初始化项目 到springboot后如…

Excel中的“LOOKUP”:熟识四个LOOKUP,可以让数据“查找”得心应手

熟识四个lookup&#xff0c;可以让数据“查找”得心应手。 (笔记模板由python脚本于2024年08月23日 19:27:16创建&#xff0c;本篇笔记适合喜欢用Excel处理数据的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖…

入门 PyQt6 看过来(项目)29 在线购物-销售分析

销售分析部分包含按月分析的簇状图和按类别分析的饼图&#xff0c;如下&#xff1a; ​ 1 页面设计 设计该页面其实很简单&#xff0c;说白了就是两个也切tab类以及饼图和簇状图。打开QTDesiger&#xff0c;按下图添加控件&#xff0c;并重命名如下&#xff1a; ​ 2 按类…

计算机视觉与视觉大模型对板书检测效果对比

文章目录 计算机视觉火山引擎ocr阿里云ocr 视觉大模型GPT4kimi通义千问chatGLM百度 全部正确某开源模型&#xff0c;效果不佳 计算机视觉 火山引擎ocr 阿里云ocr 视觉大模型 GPT4 kimi 通义千问 chatGLM 百度 全部正确 某开源模型&#xff0c;效果不佳

基于springboot的养老院管理系统的设计与实现 (含源码+sql+视频导入教程)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 基于springboot的养老院管理系统拥有多种角色账号&#xff1a;管理员和用户 管理员&#xff1a;管理员管理、用户管理、健康管理、病例方案管理、药品管理、餐饮管理、外出管理、入住管理…

汇编

汇编指令 随机数mov指令mov指令ldr指令&#xff08;伪指令&#xff09;add指令sub指令bic指令orr指令b指令cmp指令stmfd指令ldmfd指令import栈汇编指令的s后缀 随机数 1.如果某个数的数值范围是0~255之间&#xff0c;那么这个数一定是立即数&#xff1b; 2.把某个数展开成2进制…

树与图的宽度优先遍历

大致思想请参照添加链接描述该篇博客 主要地方的差异就是&#xff1a; 宽度优先遍历就是一层一层的搜索 图中数的层次题目 给定一个 n个点 m条边的有向图&#xff0c;图中可能存在重边和自环。 所有边的长度都是 1&#xff0c;点的编号为 1∼n。 请你求出 1号点到 n号点的…

C++风格指南 2、作用域

2.1. 命名空间 这段文字的关键内容概括如下&#xff1a; 1. 命名空间的使用&#xff1a;除了少数特殊情况外&#xff0c;代码应在命名空间内&#xff0c;命名空间名称应唯一&#xff0c;包含项目名和可选的文件路径。 2. 禁止使用&#xff1a; - using 指令引入整个命名空…

实验17:直流电机实验

硬件接线图; 我这里实现的是&#xff1a;转5s&#xff0c;停5s&#xff0c;循环 main.c #include<reg52.h>typedef unsigned int u16; typedef unsigned char u8;sbit ZLP1^0;void delay_10us(u16 n) {while(n--); }void delay_ms(u16 ms) {u16 i,j;for(ims;i>0;i--…

Python中8个让你成为调试高手的技巧

文末赠免费精品编程资料~~ 调试技能是每一位开发者不可或缺的利器。它不仅能帮你迅速定位并解决代码中的bug&#xff0c;还能提升你的编程效率&#xff0c;让你的代码更加健壮。今天&#xff0c;我们就来揭秘10个让你从新手进阶为调试高手的秘诀。 1. 使用print()函数——基础…

AIoTedge边缘物联网平台发布,更低的价格,更强大的功能

AIoTedge是一个创新的AI边缘计算平台&#xff0c;专为满足现代物联网&#xff08;IoT&#xff09;需求而设计。它采用了边云协同的架构&#xff0c;能够实现多点部署&#xff0c;并与IoT云平台无缝配合&#xff0c;提供分布式的AIoT处理能力。这种设计特别适合需要AI云端训练和…