【Linux】:进程间通信及管道

news2024/11/27 13:48:47

朋友们、伙计们,我们又见面了,本期来给大家带来进程间通信相关知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成!

C 语 言 专 栏:C语言:从入门到精通

数据结构专栏:数据结构

个  人  主  页 :stackY、

C + + 专 栏   :C++

Linux 专 栏  :Linux

目录

1. 进程间通信

1.1 进程间通信的目的

1.2 进程间通信的分类

2. 管道

2.1 匿名管道

2.2.1 创建原理(文件描述符角度)

2.2.2 创建原理(内核角度) 

2.2.3 管道的创建 

2.2.4 管道的4种情况

2.2.5 管道的5种特性 

2.2 命名管道

2.2.1 创建原理

2.2.2 管道的创建 

2.2.3 进程通信


1. 进程间通信

1.1 进程间通信的目的

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

进程间通信的本质:先得让不同的进程看到同一份资源。这个资源不能由进程双方的任何一方提供,通常是由OS提供。

1.2 进程间通信的分类

管道

  • 匿名管道pipe
  • 命名管道

System V 进程间通信

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

POSIX 进程间通信

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

2. 管道

我们之前在命令行使用的 | 就是一种管道,那么我们在命令行使用管道,它肯定会在底层给我们转化成对应的操作;

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

  

2.1 匿名管道

  • 当一个进程打开一个文件时,会给其分配对应的文件描述符,新打开的文件里面主要的是文件的inode(保存文件属性)、方法集(对应的读写方法)、文件页缓冲区;
  • 文件的PCB、描述文件结构体对象都是属于进程管理操作;文件描述符的分配管理属于内存操作,两者互不相干;
  • 此时如果调用fork创建子进程时,新创建的子进程根据父进程PCB为模版创建自己的PCB,子进程的文件描述符的指向和父进程指向一致(并不会重新分配);
  • 所以父进程打开的文件此时也会被子进程看到,这样子就形成了两个进程看到同一份资源,具备了进程间通信的条件;
  • 当父进程想往文件写入数据时,子进程也可以看见,但是父进程向该文件写入时,不需要再刷新到磁盘,然后子进程再从磁盘读入数据,这样效率太低下(访问外设),所以这个文件就是纯内存级文件,这个文件叫做管道文件;
  • 该管道文件可以不需要名字,并且用于父子进程通信,该管道叫做匿名管道;
  • 管道文件一旦完成资源共享,只允许单向通信。

2.2.1 创建原理(文件描述符角度)

  • ① 父进程以读写方式分别打开管道文件(父进程创建管道)

  • ② 父进程fork创建子进程

  • ③ 父子进程关闭对应的读写端

父进程为什么要以读写方式打开两次呢?

为了完成单向通信,若是只以读方式打开,那么创建子进程的时子进程也会继承读端,关闭哪一个都不能完成通信,以读写方式打开,那么子进程也会继承读写端,此时父进程关闭写端,保留读端,子进程关闭读端,保留写端就可以完成单向通信!

2.2.2 创建原理(内核角度) 

  • 以读写方式打开两次文件,文件的属性和内容只会存在一份
  • 每个文件结构体对象中都有自己对应的读写位置,所以会存在两个struct file结构体对象;
  • 因为它们的属性和内容只有一份,所以这两个struct file都会指向同样的inode、方法集、文件页缓冲区;
  • 文件结构体对象中还存在引用计数,用于记录当前有几个文件描述符指向struct file,这样就不会因为一端关闭而影响另一端。

所以,看待管道,就如同看待文件一样!管道的使用和文件一致,迎合了“Linux一切皆文件思想”

2.2.3 管道的创建 

#include <unistd.h>
// 功能:创建一无名管道
// 原型
int pipe(int fd[2]);
// 参数
// fd:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端
// 返回值:成功返回0,失败返回错误代码

代码演示:

#include <iostream>
#include <cassert>
#include <unistd.h>
#include <cstring>
#include <sys/types.h>
#include <sys/wait.h>

#define MAX_SIZE 1024

using namespace std;

int main()
{
    //1.创建管道
    int pipefd[2] = {0};
    int n = pipe(pipefd);
    assert(n == 0);
    (void)n;  //防止告警
    cout << "pipefd[0]" << pipefd[0] << "," << "pipefd[1]" << pipefd[1] << endl;

    //2.创建子进程
    pid_t id = fork();

    if(id < 0)
    {
        perror("fork");
        return 1;
    }

    //子写,父读
    //3.父子关闭不需要的fd,形成单通道通信
    if(id == 0)
    {
        //child
        close(pipefd[0]);
        //关闭读,保留写
        int cnt = 10;
        while(cnt--)
        {
            char message[MAX_SIZE];
            snprintf(message, sizeof(message), "I am child, my id: %d, %d",getpid(),cnt);
            //通过管道共享信息
            write(pipefd[1], message, strlen(message));
            sleep(1);
        }
        cout << "child close w piont" << endl;
        exit(0);
    }

    //father
    close(pipefd[1]);
    //关闭写,保留读
    char buffer[MAX_SIZE];
    //读取通过管道的信息
    while(true)
    {
        ssize_t pos = read(pipefd[0], buffer, sizeof(buffer)-1);
        if(pos > 0)
        {
            buffer[pos] = '\0';
            cout << "I am your father:" << getpid() << "child say :" << buffer << endl; 
        }
        else if(pos == 0)
        {
            cout << "child quit, me to!" << endl;
            break;
        }
        else cout << "father return val(n): " << n << endl;

        break;
        
        close(pipefd[0]);
    }

    //等待子进程
    int status = 0;
    pid_t rid = waitpid(id,&status,0);
    if(rid == id)
    {
        cout << "wait success! child exit sig:" << (status&0x7F) <<endl;
    }

    return 0;
}

2.2.4 管道的4种情况

  • 1. 正常情况,如果管道没有数据了,读端必须等待,直到有数据为止(写端写入数据了)
  • 2. 正常情况,如果管道被写满了,写端必须等待,直到有空间为止(读端读走数据)
  • 3. 写端关闭,读端一直读取, 读端会读到read()返回值为0时,表示读到文件结尾
  • 4. 读端关闭,写端一直写入,OS会直接杀掉写端进程,通过向目标进程发送SIGPIPE(13)信号,终止目标进程

2.2.5 管道的5种特性 

  • 1. 匿名管道,可以允许具有血缘关系的进程之间进行进程间通信,常用与父子,仅限于此
  • 2. 匿名管道,默认给读写端要提供同步机制
  • 3. 管道数据是面向字节流
  • 4. 管道的生命周期是随进程的
  • 5. 管道是单向通信的,是半双工通信的一种特殊情况。

2.2 命名管道

命名管道用于两个毫不相干的进程进行通信

在命令行中创建命名管道的指令叫做:mkfifo

创建好命名管道我们就可以让两个毫不相干的进程进行通信:

2.2.1 创建原理

首先两个毫不相干的进程如何看到这个管道呢?

首先命名管道有唯一的路径,并且还有文件名,所以进程就可以通过唯一的路径和文件名来找到这个管道文件,所以使用路径 + 文件名就可以让不同的进程看到同一份资源。

命名管道和匿名管道的创建原理是一样的。

2.2.2 管道的创建 

代码级别的命名管道的创建使用的是:mkfifo函数

创建成功返回0,失败返回-1,错误码被设置。

#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <cstring>
#include <cerrno>

#define FILENAME ".fifo"

int main()
{
    int n = mkfifo(FILENAME, 0666); 
    //   在当路径下创建管道文件,文件权限是0666
    if(n < 0)
    {
        std::cerr << "errno " << errno << "errstring " << strerror(errno) << std::endl;
        return 1;
    }

    return 0;
}

2.2.3 进程通信

两个进程使用命名管道进行通信操作是和文件操作一样的一个进程向文件写入,另一个进程向文件读取。

server.cc

#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <cstring>
#include <cerrno>
#include <unistd.h>

#define FILENAME "fifo"
#define SIZE 1024

int main()
{
    // 1. 创建管道文件
    int n = mkfifo(FILENAME, 0666);
    //   在当路径下创建管道文件,文件权限是0666
    if (n < 0)
    {
        std::cerr << "errno " << errno << "errstring " << strerror(errno) << std::endl;
        return 1;
    }

    // 2. 打开管道文件
    int rfd = open(FILENAME, O_RDONLY);
    if (rfd < 0)
    {
        std::cerr << "errno: " << errno << " , errstring " << strerror(errno) << std::endl;
        return 1;
    }
    std::cout << "open fifo success..." << std::endl;

    // 3, 读取信息
    char buffer[SIZE];
    while (true)
    {
        ssize_t s = read(rfd, buffer, sizeof(buffer) - 1); // 预留一个空间加上'\0'
        if (s > 0)                                         // 读取成功按照字符串的方式打印
        {
            buffer[s] = '\0';
            std::cout << "Client say# " << buffer << std::endl;
        }
        else if (s == 0) // 写端关闭,读端就要退出
        {
            std::cout << "client quit, server quit too!" << std::endl;
            break;
        }
    }
    // 4. 关闭管道文件
    close(rfd);
    std::cout << "close fifo success..." << std::endl;
    return 0;
}

client.cc

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

#define FILENAME "fifo"

int main()
{
    // 1. 打开管道文件
    int wfd = open(FILENAME, O_WRONLY);
    if (wfd < 0)
    {
        std::cerr << "errno" << errno << " , errsting:" << strerror(errno) << std::endl;
        return 1;
    }
    std::cout << "open fifo success... write" << std::endl;
    // 2. 向管道文件写入
    std::string message;
    while (true)
    {
        std::cout << "Please Enter# ";
        std::getline(std::cin, message);
        ssize_t s = write(wfd, message.c_str(), message.size());
        if (s < 0)
        {
            std::cerr << "errno: " << errno << ", errstring: " << strerror(errno) << std::endl;
            break;
        }
    }
    // 3. 关闭文件管道
    close(wfd);
    std::cout << "close fifo success..." << std::endl;

    return 0;
}

 

朋友们、伙计们,美好的时光总是短暂的,我们本期的的分享就到此结束,欲知后事如何,请听下回分解~,最后看完别忘了留下你们弥足珍贵的三连喔,感谢大家的支持!     

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

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

相关文章

“智能体风”吹进体育圈 粉丝手搓上百个智能体为中国健儿应援 太有AI了!粉丝手搓上百个智能体为中国健儿打CALL

智能体的风吹进了体育竞技圈。近日&#xff0c;在百度文心智能体平台&#xff0c;出现了上百个充满“AI”的运动明星粉丝应援智能体&#xff0c;比如支持中国女子乒乓球运动员孙颖莎的“孙颖莎的小迷妹”、支持中国女子跳水队员全红婵的“婵婵的小书包”&#xff0c;应援中国女…

中国医疗AI领头羊讯飞医疗:最新招股书显示前三月收入破亿大关!

讯飞医疗&#xff0c;医疗AI创新企业&#xff0c;收入领先市场。计划港交所上市&#xff0c;用于研发升级、产品扩展及并购。市场潜力巨大&#xff0c;未来发展可期&#xff0c;将成医疗AI璀璨明星。 各位看官&#xff0c;最近科技圈儿又有大新闻啦&#xff01;讯飞医疗科技股份…

时间序列分析方法之 -- 自回归模型(Autoregressive Model, AR)

目录 原理 适用情况 Python 示例代码 结论 原理 自回归模型&#xff08;Autoregressive Model, AR&#xff09;是一种时间序列模型&#xff0c;用于描述一个时间序列的当前值与其过去值之间的关系。自回归模型假设时间序列的当前值是其过去若干值的线性组合&#xff0c;并…

Github 2024-07-26开源项目日报 Top10

根据Github Trendings的统计,今日(2024-07-26统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Java项目2TypeScript项目2C++项目2HTML项目1Python项目1C#项目1Lua项目1JavaScript项目1Vue项目1C项目1免费编程学习平台:freeCodeCamp.org 创…

HANA-sum函数与sum() over(partition by ... order by ... )

sum函数与sum() over(partition by … order by … ) sum()函数就不介绍了。 sum() over(partition by … order by … )其实就是累加的过程具体化。 比如 有1,2,3,4 sum&#xff08;&#xff09;就会得到10 sum() over(partition by … order by … ) 就会得到&#xff1a;1,3…

leetocde662. 二叉树最大宽度,面试必刷题,思路清晰,分点解析,附代码详解带你完全弄懂

leetocde662. 二叉树最大宽度 做此题之前可以先做一下二叉树的层序遍历。具体题目如下&#xff1a; leetcode102二叉树的层序遍历 我也写过题解&#xff0c;可以先看看学习一下&#xff0c;如果会做层序遍历了&#xff0c;那么这题相对来说会简单很多。 具体题目 给你一棵…

数据结构 链式存储 +

int DeleteLinkList(LinkList *list, char *name); int ReviseLinkList(LinkList *list, char *name, DATATYPE data); int DestroyLinkList(LinkList *list); int InsertTailLinkList(LinkList *list, DATATYPE data); ​​​​​​​删除 修改​​​​​​​ 销毁 ​​​​​…

Anaconda、Pytorch安装

Anaconda 打开 Anaconda 官网 https://www.anaconda.com/ 点击右上角的 Free Download 可以选择相应的型号进行下载 如果版本不合适&#xff0c;可以进入 anaconda 的历史版本官网选择适合本机 python 版本的 anaconda 进行下载&#xff1a; https://repo.anaconda.com/arc…

Django-3.3创建模型

创建模型&#xff08;models&#xff09;的时候&#xff0c; 1&#xff1a;我们需要这个模型是哪个文件下面的模型&#xff08;models&#xff09;&#xff0c;我们需要在配置文件中吧应用安装上&#xff08;安装应用&#xff1a;INSTALLED_APPS&#xff09; 2&#xff1a;找对…

【java计算机毕设】在线考试系统java MySQL ssm jsp maven项目设计代码前后端一体 寒暑假小组作业

目录 1项目功能 2项目介绍 3项目地址 1项目功能 2项目介绍 系统功能&#xff1a; ssm在线考试管理系统包括管理员、用户俩种角色。 管理员功能包括在线考试&#xff0c;参加考试&#xff0c;我的成绩&#xff0c;我的错题&#xff0c;资源大全&#xff0c;下载资源&#xf…

GUL图形化界面操作(下部)

目录 ​编辑 前言 Swing 窗口 注意点 新增的组件 进度条组件 开关按钮 多面板和分割面板 多面板 分割面板 ​编辑 选项窗口 对话框带三个选项是&#xff0c;否&#xff0c;取消。 对话框提示输入文本: 前言 修炼中&#xff0c;该篇文章为俺很久前的学习笔记 Swi…

Matlab类阿克曼车机器人运动学演示

v1是后驱动轮轮速&#xff0c; v2是转向角变化速度&#xff0c; 实际上我们只需要关注XQ&#xff0c; YQ和Phi的变化率。 通过这三项和时间步长&#xff0c; 我们就可以计算出变化量&#xff0c; 再结合初始值就能推断出每个时刻的值。 % 清理当前运行环境 % 清除所有变量 cle…

Windosw下Visual Studio2022编译FFmpeg(支持x264、x265、fdk-acc)

FFmpeg 7.0 版本移除了 6.0 之前已弃用的 API&#xff0c;无法向下兼容。所以编译的版本选择FFmpeg 6.1.1。 一、安装Visual Studio2022 可参考另外一篇文章&#xff1a;Windows安装Visual Studio2022 QT5.15开发环境_qt5.15.2 vs2022-CSDN博客 二、安装MSYS2 下载地址&…

企业创建百度百科有什么好处?

现如今&#xff0c;网络越来越发达&#xff0c;网络营销的方法百花齐放&#xff0c;对于企业和品牌来说,想要推广产品,就是提升知名度,让更多的人知道企业和品牌。 而百度现如今在中国的搜索市场上仍是巨头,而在百度上有权威,以及能提升企业知名度的就是百度百科了。 今天&…

Linux基础复习(二)

前言 本文介绍了一下Linux命令行基本操作及网络配置 一、 命令行提示含义 [当前用户主机名 工作目录]$ 若当前用户是root&#xff0c;则最后一个字符为# 否则&#xff0c;最后一个字符为$ 二、常用Linux命令及其解释 修改主机名 一般在创建一台主机后会使用hostname相关命…

《python程序语言设计》第6章13题 数列求和编写一个函数计算

正确代码 def sumNumber(integer_num):print(" i || m(i)")print("-"*30)a 0for i in range(1, integer_num 1):a i / (i 1)print("{:4d} || {:.4f}".format(i, a))sumNumber(20)结果如下

win11 安装 Gradle

一、win11 安装Gradle(7.5.1)&#xff1a; 1.1、下载二进制包 Gradle下载页面 1.2、配置环境变量 变量名&#xff1a;GRADLE_HOME 变量值&#xff08;二进制包解压路径&#xff09;&#xff1a;D:\develop-tool\gradle-7.5.1 变量名&#xff1a;GRADLE_USER_HOME 变量值&a…

qt总结--翻金币案例

完成了一个小项目的在qt5.15.2环境下的运行,并使用NSIS editNSIS打包完成.有待改进之处:增加计时功能,随机且能通关功能,过关后选择下一关功能.打包后仅仅有安装包有图标 安装后应用图标并未改变 在qt .pro中有待改进对qt的基本操作和帮助文档有了基本的认识.对C制作小游戏有了…

Linux-IO操作之fcntl 和 ioctl

fcntl函数&#xff0c;也就是file control&#xff0c;提供了对文件描述符的各种操作。另一个常见的控制文件描述符的属性和行为的系统调用是ioctl&#xff0c;而且ioctl比fcntl能够执行更多的控制。但是&#xff0c;对于控制文件描述符常见的属性和行为&#xff0c;fcntl函数是…

认证中心:基于cookie和session实现单点登陆

流程图 参数 不同域名之下&#xff08;不同父域名&#xff09; cookiesessionredis 流程追踪 用户访问系统1的受保护资源&#xff0c;系统1发现用户未登录&#xff0c;跳转至sso认证中心&#xff0c;并将自己的地址作为参数 sso认证中心发现用户未登录&#xff0c;将用户引…