_linux 进程间通信(匿名管道)

news2024/11/23 2:47:11

文章目录

  • 1. 匿名管道
  • 2. 利用通过匿名管道实现进程间通信
    • 2.1 实现思路
    • 2.2 父子进程实现通信的简单代码
    • 2.3 结果展示如下
  • 3. 总结管道特点
  • 4. 扩展(好玩的--简单内存池)
    • 思路:
    • 代码:

1. 匿名管道

  • 查看手册(man):
    在这里插入图片描述

  • 翻译

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

  • 视图
    在这里插入图片描述

2. 利用通过匿名管道实现进程间通信

2.1 实现思路

  1. 父进程创建管道
  2. 父进程fork子进程(这样子和父进程就可以进行通信了)
  3. 父进程关闭fd[0]–读,子进程关闭fd[1]–写
    在这里插入图片描述

2.2 父子进程实现通信的简单代码

  • 要求:
    • 父进程向管道当中写“i am father”,
    • 子进程从管道当中读出内容, 并且打印到标准输出
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <unistd.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/wait.h>


using namespace std;
int main()
{
    //1. 创建管道
    int pipefd[2]={0};  //pipefd[0] 读, pipefd[1]写
    int n=pipe(pipefd);
    assert(n!=-1);
    (void)n;    //debug assert , release assert


#ifdef DEBUG 
    cout<<"pipefd[0]: "<<pipefd[0]<<endl;
    cout<<"pipefd[1]: "<<pipefd[1]<<endl;
#endif    
    //2. 创建子进程
    pid_t id=fork();
    assert(id !=-1);
    if(id==0)
    {
        //子进程
        //3. 构建单项通道,子进程读取,父进程写入
        //3.1 关闭子进程不需要的fd
        close(pipefd[1]);
        char buffer[1024];
        while(true)
        {
            ssize_t s=read(pipefd[0], buffer, sizeof(buffer)-1);
            if(s>0)
            {
                buffer[s]=0;
                cout<<"Father:"<<buffer<<endl;
            }
            break;
        }
        exit(0);
    }
    
    //父进程
    //3. 构建单项通道,子进程读取,父进程写入
    //3.1 关闭父进程不需要的fd
    close(pipefd[0]);
    string message="i am father";
    int count=0;
    char send_buffer[1024];
    while(true)
    {
        //3.2 变化的字符串
        snprintf(send_buffer, sizeof(send_buffer), "%s", message.c_str());
        //3.3写入
        write(pipefd[1], send_buffer, strlen(send_buffer));
        break;
    }


    pid_t ret = waitpid(id, nullptr, 0);
    assert(ret!=-1);
    (void)ret;
    return 0;
}
  • 注意:
    子进程必须等父进程写完才能读;也就是父进程再写的时候子进程在阻塞式等待。

2.3 结果展示如下

在这里插入图片描述

3. 总结管道特点

  1. 管道是用于进行具有血缘关系的进程进行进程通信的–常用于父子通信
  2. 管道具有通过让进程间协同,提供了访问控制!
  3. 管道提供的是面向流式的通信服务–面向字节流–协议
  4. 管道是基于文件的,文件的生命周期随进程的,即管道的生命周期随进程的。
  5. 管道是单项通信的,就是半双工通信的一种特殊情况。

4. 扩展(好玩的–简单内存池)

  • 父进程创建多个进程,父进程给每个进程分发任务(单机版的负载均衡也就随机种子srand)。

思路:

创建多个进程,子进程按找父进程发送的指令执行任务;创建的每个进程的pid和匿名管道fd[1]利用pair包装后用vector存起来。

1. 任务表

using func = std::function<void()>;

std::vector<func> callbacks;	//任务调用(根据下标)
std::unordered_map<int, std::string> desc;	//任务栏信息

2. 子进程读取命令

int waitCommand(int waitFd, bool &quit) //如果对方不发,我们一直阻塞式等待

3. 父进程唤醒子进程(写入管道,也就是输入指令)

void sendAndWakeup(pid_t who, int fd, uint32_t command)

规定:4字节输入流

代码:

#include <iostream>
#include <unistd.h>
#include <cstdio>
#include <ctime>
#include <cassert>
#include <sys/wait.h>
#include <sys/types.h>
#include <vector>
#include <string>
#include "Task.hpp"

using namespace std;

int waitCommand(int waitFd, bool &quit) //如果对方不发,我们一直阻塞式等待
{
    uint32_t command = 0;
    ssize_t s = read(waitFd, &command, sizeof(command));
    if (s == 0) //退出
    {
        quit = true;
        return -1;
    }
    assert(s == sizeof(uint32_t));

    return command;
}

void sendAndWakeup(pid_t who, int fd, uint32_t command)
{
    write(fd, &command, sizeof(command));
    cout << "主进程: 唤醒进程: " << who << " 命令: " << desc[command] << "通过: " << fd << endl;
}

#define process_Num 5
int main()
{
    load();
    // pid, pipefd
    vector<pair<pid_t, int>> slots;
    //创建多个进程
    for (int i = 0; i < process_Num; i++)
    {
        //创建管道
        int pipefd[2] = {0};
        int n = pipe(pipefd);
        assert(n != -1);
        (void)n;

        pid_t id = fork();
        assert(id != -1);
        //子进程读取
        if (id == 0)
        {
            // child
            //关闭写端
            close(pipefd[1]);
            while (true)
            {
                // pipefd[0]
                //等命令
                bool quit = false;
                int command = waitCommand(pipefd[0], quit); //如果对方不发,我们一直阻塞式等待
                if (quit)
                    break;
                //执行命令
                if (command >= 0 && command < handlerSize())
                {
                    callbacks[command]();
                }
                else
                {
                    cout << "非法command: " << command << endl;
                }
            }
            exit(0);
        }
        // father
        //父进程写入
        //关闭读端
        close(pipefd[0]); // pipefd[1]
        slots.push_back(make_pair(id, pipefd[1]));
    }

    //开始任务 父进程派发任务
    srand((unsigned long)time(nullptr) ^ getpid() ^ 303200109240139); //让我们的数据源更随机
    while (true)
    {
        //选择任务
        int command = rand() % handlerSize();
        //选择进程
        int choice = rand() % slots.size();
        //布置任务给指定进程
        sendAndWakeup(slots[choice].first, slots[choice].second, command);
        sleep(2);
        // int select;
        // int command;
        // cout << "######################################################" << endl;
        // cout << "#        1. show functions   2.send command          #" << endl;
        // cout << "######################################################" << endl;
        // cout << "please select> ";

        // cin >> select;
        // if (select == 1)
        //     showHandler();
        // else if (select == 2)
        // {
        //     cout << "输入你的指令> ";
        //     //选择任务
        //     cin >> command;
        //     //选择进程
        //     int choice = rand() % slots.size();
        //     //布置任务给指定进程
        //     sendAndWakeup(slots[choice].first, slots[choice].second, command);
        // }
        // else
        // {
        // }
    }
    //关闭fd  所有的子进程退出
    for (const auto &slot : slots)
    {
        close(slot.second);
    }
    //回收所有子进程信息
    for (const auto &slot : slots)
    {
        waitpid(slot.first, nullptr, 0);
    }
    return 0;
}
#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <unistd.h>
#include <functional>

using func = std::function<void()>;

std::vector<func> callbacks;
std::unordered_map<int, std::string> desc;

void readMySQL()
{
    std::cout << "sub process[" << getpid() << "] 执行访问数据库的任务\n" << std::endl;
}

void execuleUrl()
{
    std::cout << "sub process[" << getpid() << "] 执行Url解析\n" << std::endl;
}

void cal()
{
    std::cout << "sub process[" << getpid() << "] 执行加密任务\n" << std::endl;
}

void save()
{
    std::cout << "sub process[" << getpid() << "] 执行数据持久化任务\n" << std::endl;
}

//任务表
void load()
{
    desc.insert({callbacks.size(), "readMySQL: 读取数据库"});
    callbacks.push_back(readMySQL);

    desc.insert({callbacks.size(), "execuleUrl: 进行Url解析"});
    callbacks.push_back(execuleUrl);

    desc.insert({callbacks.size(), "cal: 执行加密"});
    callbacks.push_back(cal);

    desc.insert({callbacks.size(), "save: 执行数据持久化"});
    callbacks.push_back(save);
}

//展示多少任务
void showHandler()
{
    for (const auto &iter : desc)
    {
        std::cout << iter.first << "\t" << iter.second << std::endl;
    }
}

//多少方法
int handlerSize()
{
    return callbacks.size();
}

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

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

相关文章

[附源码]计算机毕业设计JAVA基于JSP技术的新电商助农平台

[附源码]计算机毕业设计JAVA基于JSP技术的新电商助农平台 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; …

Amine-PEG-Azide,NH2-PEG-N3,胺-PEG-叠氮PEG试剂供应

1、名称 英文&#xff1a;Amine-PEG-Azide&#xff0c;NH2-PEG-N3 中文&#xff1a;胺-聚二乙醇-叠氮 2、CAS编号&#xff1a;N/A 3、所属分类&#xff1a;DSPE PEG Azide PEG 4、分子量&#xff1a;可定制&#xff0c;NH2-PEG-N3 2000、胺-聚二乙醇-叠氮 10000、NH2-PEG-…

从零开始做一款Unity3D游戏<一>——亲自上手使用Unity

游戏设计入门 游戏设计文档 Hero Born游戏的单页文档 构建关卡 创建基本图形 在三维中思考 材质 白盒环境 光照基础 创建光源 Light组件的属性 在Unity中制作动画 创建动画片段 记录关键帧 曲线与切线 粒子系统 总结 本文主要来自<<C#实践入门>>哈…

【单片机】独立看门狗IWDG初始化

目录 看门狗简介&#xff1a; 初始化例子&#xff1a; 看门狗使能&#xff1a; 写保护&#xff1a; 看门狗重载&#xff1a; 看门狗复位时间计算&#xff1a;基本上看stm中文手册对照框图就很明确 看门狗简介&#xff1a; 此器件具有两个嵌入式看门狗外设&#xff0c;具有…

3-4数据链路层-局域网

文章目录一.基本概念1.网络拓扑2.传输介质3.介质访问控制方法4.局域网的分类5.逻辑链路控制&#xff08;LLC&#xff09;子层与媒体接入控制&#xff08;MAC&#xff09;子层二.以太网&#xff08;一&#xff09;以太网的传输介质与网卡1.传输介质2.网卡&#xff08;二&#xf…

[附源码]计算机毕业设计JAVA基于JSP学生信息管理系统

[附源码]计算机毕业设计JAVA基于JSP学生信息管理系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM …

工具及方法 - 编辑二进制文件(使用VSCode和Notepad++的插件Hex Editor)

Visual Studio Code 在VSCode里安装插件&#xff0c;可以实现很多功能。 打开VSCode&#xff0c;在菜单里选择&#xff0c; View->Extensions&#xff0c;就会出现扩展插件的查找页面。 输入想要查找的插件名称&#xff0c;搜索&#xff0c;然后点击安装。 比如要用VSCode…

高性能零售IT系统的建设06-当应对大量HTTP请求时兼顾性能、处理速度的架构设计

前言 这个系列不像我的那些个“保姆式”教程&#xff0c;那些保姆式教程我一周最多可以写8篇&#xff0c;因为太简单了。充其量花的时间就是用“看漫画”的方式去组织我的截图和尽量少文字多Sample。 而高性能系统建设系列这一块不仅仅只有代码&#xff0c;相反它甚至不会多写…

力扣(LeetCode)25. K 个一组翻转链表(C++)

模拟 前置知识 : 反转链表、两两交换链表中的节点 。 LeetCode 有相应题目&#xff0c;可以先做。 设置哑结点 &#xff0c; 便于操作头结点。 翻转至少要 kkk 个结点 &#xff0c; 先检查剩余结点够不够 kkk 个。 不够 kkk 个就翻转完成了。 翻转分为组内翻转和首尾变向两步…

查找xml文件

一 前言 相比xml.dom.minidom&#xff0c;lxml.etree具有高效的查找方法&#xff0c;更方便&#xff0c;直接&#xff1b; 二、知识点&#xff1a;查找感兴趣的元素 举例一&#xff1a;递归遍历其下的所有子树&#xff08;包括子级&#xff0c;子级的子级&#xff0c;等等 …

nero platinum刻录光盘简要教程(文章末尾有教程链接)

nero platinum suit 介绍 使用nero express可以完成多数情况下的光盘应用。在nero platinum suit中单击nero express&#xff0c;这时可以看到nero express的工作界面&#xff0c;在这里面可以刻录数据光盘&#xff0c;可以刻录音乐光盘&#xff0c;可以刻录视频光盘&#xff…

SpringMVC集成静态资源

集成静态资源 静态资源&jsp是被谁处理的 tomcat是一个servlet容器&#xff0c;servlet容器中通常有servlet来处理各种请求&#xff0c;那么当访问静态资源或者jsp的时候&#xff0c;当然也是有servlet来处理这些请求的&#xff0c;但是并未在web.xml中配置哪个servlet来处…

SpringBoot+Vue项目小区疫苗接种管理系统的设计与实现

文末获取源码 开发语言&#xff1a;Java 使用框架&#xff1a;spring boot 前端技术&#xff1a;JavaScript、Vue 、css3 开发工具&#xff1a;IDEA/MyEclipse/Eclipse、Visual Studio Code 数据库&#xff1a;MySQL 5.7/8.0 数据库管理工具&#xff1a;phpstudy/Navicat JDK版…

MySQL数据库JDBC编程

目录 前言&#xff1a; 项目中导入驱动包 插入记录 创建数据源 连接数据库 构造sql语句 执行sql语句 释放资源 整体代码展示 查看数据 代码展示 小结&#xff1a; 前言&#xff1a; MySQL为Java提供了驱动包。通过Java程序实现的客户端&#xff0c;可以通过这个驱动…

JavaWeb以Maven整合Mybatis报错java.lang.NoClassDefFoundError(Web项目未能完全加载Maven下的依赖)

问题描述 为完成学校课程一个javaweb的demo&#xff0c;想着对数据库的访问能够更加简洁&#xff0c;所以用了Mybatis。因为之前有过Springboot整合Mybatis经验&#xff0c;所以本以为事情会简单。在Junit的测试类中是能够正常对数据库进行CRUD。在Javaweb的Servlet类中调用数据…

应用层协议之DNS、DHCP

运输层为应用进程提供了端对端的通信服务&#xff0c;但不同的网络应用的应用进程之间&#xff0c;还需要有不同的通信规则。因此在运输层协议之上&#xff0c;还需要有应用层协议。 应用层中有这些常见的协议 域名系统&#xff1a;DNS动态主机配置&#xff1a;DHCP超文本传输…

数据结构之栈

文章目录前言一、栈二、栈应该如何实现1.顺序表or链表2.静态or动态三、栈的实现1.栈的定义2.接口&#xff08;声明&#xff09;3.接口的实现初始化栈销毁栈获取栈顶元素获取栈中有效元素个数入栈出栈检测栈是否为空4.主函数&#xff08;测试&#xff09;总结前言 今天这篇文章…

云原生系列 二【轻松入门容器基础操作】

✅作者简介&#xff1a; CSDN内容合伙人&#xff0c;全栈领域新星创作者&#xff0c;阿里云专家博主&#xff0c;华为云云 享专家博主&#xff0c;掘金后端评审团成员 &#x1f495;前言&#xff1a; 最近云原生领域热火朝天&#xff0c;那么云原生是什么&#xff1f;何为云原生…

excel的frequency函数的用法和实例

目录 1.语法和用法 &#xff08;1&#xff09;语法&#xff1a;frequency(data_array,bins_array) &#xff08;2&#xff09;用法&#xff1a;用于统计指定分组区间的频率&#xff0c;以已裂垂直数组返回一组数据的频率分布。 2.实例 &#xff08;1&#xff09;分组统计各…

【WxPusher消息推送平台】js版对接发送消息教程实战案例,JavaScript版调用axios发送消息实例。保姆级教程

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言一、WxPusher消息推送平台是什么1、注册自己的WxPusher2、扫码关注应用&#xff0c;获得你的UID二、使用步骤1.封装axios方法2.编写发送消息方法总结前言 WxPus…