波奇学Linux:进程通信管道

 进程通信

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

创建父子进程,使得进程的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 codeWriter(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 pipeint pipefd[2];int n=pipe(pipefd);assert(!n); // n=0 successpid_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 fdfor(auto oldfd:oldfds){std::cout<<oldfd<<" ";close(oldfd);}std::cout<<std::endl;//build relationshipclose(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 taskLoadTask(&tasks);//PrintTask(tasks);InitProcessPool(&channels);ctrlSlaver();quitProcess(channels);return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

利用psutil库检查脚本是否在运行

摘要 如果要判断某一脚本是否在运行&#xff0c;可以通过psutil库获取所有进程的cmdline&#xff0c;并判断指定的文件名是否在cmdline中。 目录 1.psutil库简介 2.检查代码及说明 2.1检查思路 2.2异常捕获 2.3执行方法 1.psutil库简介 psutil 是一个跨平台&#xff08;…

力扣随笔之寻找重复数(中等287)

思路1&#xff1a;暴力解法&#xff0c;根据要求不修改数组且只用常量级O(1)的额外空间&#xff0c;我们写两层嵌套循环&#xff0c;寻找重复的数;可以解决部分问题&#xff0c;但会超出时间限制无论Java还是C; Java实现&#xff1a; class Solution {public int findDuplicat…

LeetCode--代码详解 235.二叉搜索树得最近公共祖先

235.二叉搜索树得最近公共祖先 题目 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个结点 p、q&#xff0c;最近公共祖先表示为一个结点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽可…

设计模式-结构型模式-桥接模式

桥接模式&#xff08;Bridge Pattern&#xff09;&#xff1a;将抽象部分与其实现部分分离&#xff0c;使它们都可以独立地变化。它是一种对象结构型模式&#xff0c;又称为柄体&#xff08;Handle and Body&#xff09;模式或接口&#xff08;Interface&#xff09;模式。桥接…

linux 0.11 调试c代码

我们可以通过实验楼实验环境 来调试linux0.11的c代码。 cd ~/oslab/ tar -zxvf hit-oslab-linux-20110823.tar.gz -C ~ cd ~/oslab/linux-0.11/ make cd ~/oslab/ nohup ./dbg-c & nohup terminator & ls在新的窗口执行 ./rungdb,进入调试状态。 输入 set disassemb…

Selenium WebDriver + python 自动化测试框架

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

个人健康|个人健康管理小程序|基于微信小程序的个人健康管理系统设计与实现(源码+数据库+文档)

个人健康管理小程序目录 目录 基于微信小程序的个人健康管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、微信小程序前台 2、管理员后台 &#xff08;1&#xff09;用户信息管理 &#xff08;2&#xff09;运动教程管理 &#xff08;3&#xff09;公告…

自考《计算机网络原理》考前冲刺

常考选择填空 1、计算机网络的定义&#xff1a;计算机网络是互连的、自治的计算机的集合。 2、协议的定义&#xff1a;协议是网络通信实体之间在数据交换过程中需要遵循的规则或约定 3、协议的3个要素 (1) 语法&#xff1a;定义实体之间交换信息的格式与结构&#xff0c;或…

[树形DP] 树的最大独立集

题目 这个挺简单的&#xff0c;注意状态转移时&#xff0c;如果选这个点&#xff0c;那么它的子结点状态应该为不选&#xff0c;如果这个点的状态是不选&#xff0c;那么可以在它的子结点里选择&#xff1a;选/不选两个状态&#xff0c;所以最后结果是max挑选。 #include<b…

创作纪念日:记录我的成长与收获

机缘 一开始是在我深入学习前端知识的Vue.js框架遇到了一个问题&#xff0c;怎么都解决不了&#xff0c;心烦意乱地来csdn上找解决方法。开心的是真被我找到了&#xff0c;真的很感恩&#xff0c;也意识到在这个平台上分享自己的经验是多么有意义的事情&#xff0c;可能随便的…

Android Gradle 开发与应用 (一) : Gradle基础

1. Gradle是什么 Gradle是一个通用的构建工具&#xff0c;支持诸多主要的 IDE&#xff0c;包括 Android Studio、IntelliJ IDEA、Visual Studio 等 Gradle 的底层实现(核心引擎和框架)其实是用 Java 编写的开发者通常使用 Groovy 或 Kotlin 来编写构建脚本 1.1 那么为什么Gra…

QC七大工具

目录 1、检查表&#xff1a; 2、层别法&#xff1a; 3、柏拉图&#xff1a; 4、因果图&#xff1a; 5、散布图&#xff1a; 6、直方图&#xff1a; 7、控制图&#xff1a; QC是英文Quality Control的简称&#xff0c;中文意思是质量控制。在ISO9000:2015对质量管理&…