波奇学Linux:进程通信管道

news2024/9/22 22:28:31

 进程通信

管道:基于文件级别的单向通信

创建父子进程,使得进程的struct file*fd_array[]的文件描述符指向同一个struct file文件,这个文件是内存级文件。

父进程关写端,子进程再关闭读端。实现单向通信

子进程写入,父进程读取。

如果进程不是父子关系,则无法利用管道,因此管道应用于父子或者兄弟进程

以上的管道叫做匿名管道。

创建管道:pipe

输出型参数

pipefd[0]读下标

pipefd[1]写下标

代码示例

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

using namespace std;
#define N 2
#define NUM 1024
void Writer(int wfd)
{
    string s="hello I am child";
    pid_t self=getpid();
    int number=0;

    char buffer[NUM];
    while(true)
    {
        buffer[0]=0; //字符串清空
        //将字符串的内容放入buffer缓冲区中
        snprintf(buffer,sizeof(buffer),"%s-%d-%d",s.c_str(),self,number++);
        cout<<buffer<<endl;
        // 发送给父进程
        write(wfd,buffer,strlen(buffer));
        sleep(1);

    }
}
void Reader(int rfd)
{
    char buffer[NUM];
    while(true)
    {
        buffer[0]=0;
        // n表示实际读到字节的大小
        ssize_t n=read(rfd,buffer,sizeof(buffer));
        if(n>0)
        {
            buffer[n]=0; //当成字符串加入"\0"
            cout<<"father get a message["<<getpid()<<"]#"<<buffer<<endl;
        }
    }
}
int main()
{
    int pipefd[]={0};
    int n=pipe(pipefd);
    if(n<0) return 1;
    cout<<"pipefd[0]:"<<pipefd[0]<<", pipefd[1]: "<<pipefd[1]<<endl;
    pid_t id=fork();
    if(id<0) return 2;
    if(id==0) 
    {
        close(pipefd[0]);
        //IPC code
        Writer(pipefd[1]);
        close(pipefd[1]);
        exit(0);
    }
    close(pipefd[1]);
    Reader(pipefd[0]);
    pid_t rid=waitpid(id,nullptr,0);
    if(rid<0) return 3;
    close(pipefd[0]);

    return 0;
}

然而多执行流会会出现访问冲突的问题--父进程访问的数据到一半时,旧数据被写端覆盖。

父子进程协同,保护管道文件数据安全

读写端正常,如果管道为空,读端阻塞

管道文件有大小,写满写端阻塞

读端正常读,写端关闭,写进程变成僵尸进程,读端就会读到0,表明读到文件结尾,而且不会阻塞

写端正常写,读端关闭,操作系统通过信号杀掉写入的进程。

ulimit查看pipe size大小,但是不同内核可能有差别

管道面向字节流,一次性读完,有多少读多少,且将分割符看成一个普通字符,管道规范可以解决这个问题

管道是基于文件的,文件的生命周期是随进程的

管道的应用场景

使用管道实现简易版本的进程池

 Task.hpp

#pragma once
#include<cstdlib>
#include<iostream>
#include<vector>
#include<unistd.h>
#include<assert.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<string>
typedef void (*task_t)();
std::vector<task_t> tasks;

//任务是四个函数
void task1()
{
    std::cout<<"task 1 call"<<std::endl;
}
void task2()
{
    std::cout<<"task 2 call"<<std::endl;
}
void task3()
{
    std::cout<<"task 3 call"<<std::endl;
}
void task4()
{
    std::cout<<"task 4 call"<<std::endl;
}
// const & 输入 ->向函数内部输入
// * 输出
// & 输入 输出
void LoadTask(std::vector<task_t> *p_tasks)
{
    p_tasks->push_back(&task1);
    p_tasks->push_back(&task2);
    p_tasks->push_back(&task3);
    p_tasks->push_back(&task4);
}

 ProcessPool.cc

#include "Task.hpp"
//对管道进行描述

#define processnum 10
class channel
{
public:
    channel(int task_id,int pid,std::string processname)
        :_cmdfd(task_id)
        ,_pid(pid)
        ,_processname(processname)
        {}
public:
    int _cmdfd;
    int _pid;
    std::string _processname;
};
std::vector<channel> channels;
void slaver()
{
    while(true)
    {
        int tasknum=0;
        ssize_t num=read(0,&tasknum,sizeof(int));//read block,等待输入
        
        // tasknum=tasknum%tasks.size();
        // (*tasks[tasknum])();
        //std::cout<<"i and pid"<<i<<pid<<std::endl;
        if (!num)break;
        else
        {
            std::cout<<"child process "<<getpid()<<"pid: "<<"receive task_id: "<<tasknum<<std::endl;
            (*tasks[tasknum])();
        }
    }
}
void InitProcessPool(std::vector<channel>* pchannels)
{
    std::vector<int> oldfds;
    for (int i=0;i<processnum;i++){
        //create pipe
        int pipefd[2];
        int n=pipe(pipefd);
        assert(!n); // n=0 success
        
        pid_t pid=fork();
        assert(pid!=-1); //pid =-1 fail
        //child
        //std::cout<<"i = "<<i;
        if(pid==0)
        {   std::cout<<"child process:"<<getpid()<<"have otherfds: ";
            //only one write fd
            for(auto oldfd:oldfds)
            {
                std::cout<<oldfd<<" ";
                close(oldfd);
            }
            std::cout<<std::endl;
            //build relationship
            close(pipefd[1]);
            // pipe read from fd=0 not fd=3;
            dup2(pipefd[0],0);
            close(pipefd[0]);
            // 
            slaver();
            exit(0);
        }
        close(pipefd[0]);
        int status=0;
        // ensure one by one ,block until child process finish
        // pid_t result=waitpid(pid,&status,0);
        // assert(result!=-1);
        pchannels->push_back(channel(pipefd[1],pid,"process "+std::to_string(i)));
        oldfds.push_back(pipefd[1]);
        sleep(1);
    }
    
}
void menu()
{
    std::cout<<"*********************"<<std::endl;
    std::cout<<"******1.task one*****"<<std::endl;
    std::cout<<"******2.task two*****"<<std::endl;
    std::cout<<"******3.task three***"<<std::endl;
    std::cout<<"******4.task four****"<<std::endl;
    std::cout<<"******0.quit*********"<<std::endl;
    std::cout<<"*********************"<<std::endl;
}
void ctrlSlaver()
{
    int which=0;
    while(true)
    {
        menu();
        int enter=0;
        std::cout<<"enter number:";
        std::cin>>enter;
        std::cout<<std::endl;
        
        if (enter==0){
            std::cout<<"quit software"<<std::endl;
            //ssize_t n=write(0,&enter,0); 不用写入,直接退出就好了
            //assert(n!=-1);
            break;
        }
        ssize_t n=write(channels[which]._cmdfd,&enter,sizeof(int));
        assert(n!=-1);
        std::cout<<"parent send a task_num "<<enter<<" to process "<<channels[which]._processname<<std::endl;
        which++;
        which=which%processnum;
    }
}
void quitProcess(std::vector<channel>& pchannels)
{
    for(auto channel:channels)
    {
        std::cout<<"close process"<<channel._pid<<std::endl;
        //关闭读端,进程关闭
        close(channel._cmdfd);
        wait(NULL);
    }
    
}
void PrintTask(const std::vector<task_t> tasks)
{

    for(auto task:tasks)
    {
        (*task)();
    }

}
int main()
{
    // load the task
    
    LoadTask(&tasks);
    //PrintTask(tasks);
    InitProcessPool(&channels);
    ctrlSlaver();
    quitProcess(channels);
    return 0;
}

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

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

相关文章

个人博客搭建

使用彩虹云主机百度云域名WordPress 下载WordPress https://cn.wordpress.org/ 购买主机 购买彩虹云主机&#xff0c;购买香港高防主机https://www.cccyun.net/ 购买之后点击 管理 进入后点 击前往控制面板 -> 一键登录控制面板 可进入控制面板。 选择文件管理 在线…

cuda加速:memory coalescing,Bank Conflicts

cuda加速&#xff1a;memory coalescing 1.memory coalescing2.Shared Memory Bank Conflicts参考文献 1.memory coalescing 参考【1】中给出的定义&#xff1a;一个warp中&#xff0c;thread 0到thread 31访问连续的内存空间&#xff0c;则这些线程的访问被合并为一次访问。 …

2.21学习总结

1.【模板】ST 表 2.Balanced Lineup G 3.景区导游 4.最近公共祖先&#xff08;LCA&#xff09; 倍增思想&#xff1a;主要用于LCA问题&#xff0c;RMQ问题。在进行 递推 时&#xff0c;如果 状态空间很大&#xff0c;通常的 线性递推 无法满足 时间 与 空间复杂度 的要求&…

BabylonJS 6.0文档 Deep Dive 动画(一):动画介绍

1. 动画介绍 无论动画如何实现&#xff0c;它都必须考虑所需的动作、时间、产生所需流动性所需的帧数以及序列中的关键点。这个介绍应该有助于理解Babylon.js是如何进行动画的&#xff0c;以及它们是如何实现的。 动画由一系列图像、帧生成&#xff0c;这些图像、帧一个接一个地…

做跨境电商,为什么要建独立站,2024年的机会在哪里?一次性讲清楚...

做跨境电商&#xff0c; 是选择依托第三方平台&#xff1f; 还是自建独立网站&#xff1f; 01 什么是自建独立站 最简单的说法&#xff1a;独立站对于我们跨境电商这个行业来说&#xff0c;就是那些不是主流平台的网站&#xff0c;是某个企业或者个人自己做和运营的搭建电商…

记录一次调用奇门api报错信息Invalid signature (签名无效)

奇门有msg对应错误的记录 我可能是 3.1 以下是还原场景 第一个方法 private static String getSellerItem() throws IOException {Map<String, String> params new HashMap<String, String>();// 公共参数params.put("page_index", "100"…

如何用USB服务器解决网银U盾连接管理问题?好用吗?

反复插拔效率低、分散管理隐患大 随着信息化建设的深入推进&#xff0c;网银U盾已经成为企业办公中不可或缺的工具。然而&#xff0c;在使用U盾的过程中&#xff0c;常常会遇到一些问题&#xff0c;其中最突出的问题之一就是U盾的连接和管理问题。反复插拔效率低、分散管理隐患…

Leetcode - 周赛385

目录 一&#xff0c;3042. 统计前后缀下标对 I 二&#xff0c;3043. 最长公共前缀的长度 三&#xff0c;3044. 出现频率最高的质数 四&#xff0c;3045. 统计前后缀下标对 II 一&#xff0c;3042. 统计前后缀下标对 I 该题数据范围小&#xff0c;可直接暴力求解&#xff0c;…

18.贪心算法

排序贪心 区间贪心 删数贪心 统计二进制下有多少1 int Getbit_1(int n){int cnt0;while(n){nn&(n-1);cnt;}return cnt; }暴力加一维前缀和优化 #include <iostream> #include <climits> using namespace std; #define int long long const int N2e510; in…

利用AI做Q版影视剧人物头像,轻松涨粉过万

粉丝在问,能不能出一个SD制作热播影视剧Q版人物的教程。刚好我最近也刷到了几个号,对这方面也感兴趣,于是去研究了出图的逻辑。热播电视剧的Q版人物,一方面不缺流量,IP也能带来一波回忆杀。 下面这组图是一只小鹿鸭的作品,在某音和某书都有很好的数据。 公众号刷到了一组…

128.乐理基础-五线谱-纯四度、纯五度

内容参考于&#xff1a;三分钟音乐社 上一个内容&#xff1a;127.乐理基础-五线谱-纯一度、纯八度-CSDN博客 上一个内容里练习的答案&#xff1a; 纯四度、纯五度的结论 纯四度例子&#xff1a; 例子1&#xff1a; 例子2&#xff1a; 纯四度两个条件&#xff0c;音数是2.5&a…

微信小程序开发学习笔记——2.10video视频组件及uniCloud云存储网络地址用法

>>跟着b站up主“咸虾米_”学习微信小程序开发中&#xff0c;把学习记录存到这方便后续查找。 课程连接&#xff1a; https://www.bilibili.com/video/BV19G4y1K74d?p13&vd_source9b149469177ab5fdc47515e14cf3cf74 一、最简单的放video的例子 视频尽量不要放本…

华为OD机试真题-整数对最小和-2023年OD统一考试(C卷)-- Python3-开源

题目&#xff1a; 考察内容&#xff1a;双循环sortsum 代码&#xff1a; """ 题目分析&#xff1a; 求随机组合最小和 输入&#xff1a; 数组a个数&#xff0c; 数组元素 数组b个数&#xff0c;数组元素 对数个数输出&#xff1a; 和的最小值3 1 1 2 3 1 2 3…

【GPTs分享】每日GPTs分享之Canva

简介 Canva&#xff0c;旨在帮助用户通过Canva的用户友好设计平台释放用户的创造力。无论用户是想设计海报、社交媒体帖子还是商业名片&#xff0c;Canva都在这里协助用户将创意转化为现实。 主要功能 设计生成&#xff1a;根据用户的描述和创意需求&#xff0c;生成定制的设…

Java Z 垃圾收集器 (ZGC):彻底改变内存管理

欢迎来到百战百胜&#xff01;我们致力于为广大IT从业者、学生和爱好者提供全面、实用的资源和服务。加入我们的聊天群&#xff0c;这里有专业大佬为你提供有价值的建议和指导&#xff01; 微信搜索&#xff1a;IT开DD那点小事 更多访问&#xff1a;www.besthub.tech Z 垃圾收集…

【LeetCode】63. 不同路径 II(中等)——代码随想录算法训练营Day39

题目链接&#xff1a;63. 不同路径 II 题目描述 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish”&#xff09;。…

快速将excel/word表格转换为web页面(html)的方法

前言 在进行开发企业信息化建设的过程&#xff0c;应该有很多这样的场景&#xff0c;就是将现有的电子表格记录的方式转换为在数据系统中进行网页上报。也就是需要根据当前一直使用的表格制作一个上传这个表格信息的网页&#xff0c;如果要减少系统的使用学习成本&#xff0c;…

道本合规管理|| 欧盟对苹果公司的重罚与合规警示

近日&#xff0c;外媒广泛报道了欧盟委员会预计将对美国科技巨头苹果公司开出约5亿欧元的罚单。这一决定源于苹果公司在音乐流媒体服务领域的反竞争行为&#xff0c;违反了欧盟严格的反垄断法规。这一事件不仅揭示了企业在全球化经营中面临的合规挑战&#xff0c;也为我们提供了…

解决app中以webview的方式嵌入h5网页,h5网页加载不出来

问题描述&#xff1a;我的h5网页在web端和手机浏览器都能正常渲染展示&#xff0c;但是嵌入到客户的webview中&#xff0c;渲染加载不出来&#xff0c;仔细检查代码之后并没有任何代码错误和后台报错。抓耳挠腮查找两天之后发现&#xff0c;原因为整个h5网页的最外层高度设置成…

ProtoBuf认识与Windows下的安装

protobuf简介 Protobuf 是 Protocol Buffers 的简称&#xff0c;它是 Google 公司开发的一种数据描述语言&#xff0c;是一种轻便高效的结 构化数据存储格式&#xff0c;可以用于结构化数据&#xff0c;或者说序列化。它很适合做数据存储 或 RPC 数据交换格 式 。可用于通讯…