精彩管道不会梦到深沉蓝调

2024-08-26 04:44

本文主要是介绍精彩管道不会梦到深沉蓝调,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

如果上天开了眼

请多给我点蓝调

多给我点沙锤

多给我点甲壳

让我吃鸡!

星元自动机,新的版本之神 

给宁磕一个

完蛋

你说这不是问题吗

我这篇文章从我写开始,到写完

炉石都换赛季了!!!!!

伙伴没了我心碎

#include<iostream>
#include<string>
#include<vector>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include"Task.hpp"// void work(int rfd)
// {
//     while(true)
//     {
//         int command = 0;
//         int n = read(rfd, &command,sizeof(command)); 
//         if(n == sizeof(int))
//         {
//             std::cout << "pid is:" << getpid() << "handler task" << std::endl;
//             ExcuteTask(command);
//         }
//         else if(n == 0)
//         {
//             std::cout<<"Pipe closed"<<std::endl;
//             break;
//         }
//         else
//         {
//             perror("read");
//             break;
//         }
//     }
// }//masterclass Channel
{
public:Channel(int wfd, pid_t id, const std::string &name):_wfd(wfd),_subprocessid(id),_name(name){}int Getfd()const{return _wfd;}pid_t GetProcessId()const{return _subprocessid;}std::string GetName()const{return _name;}void CloseChannel(){close(_wfd);}void Wait(){pid_t rid = waitpid(_subprocessid,nullptr,0);if(rid > 0){std::cout << "wait " <<rid << "success" << std::endl;}}~Channel(){}
private:int _wfd;pid_t _subprocessid;std::string _name;
};void CreateChannelAndSub(std::vector<Channel>* channels,int num1,task_t task)
{for(int i = 0; i < num1; i++){//创建管道int pipefd[2] = {0};int n = pipe(pipefd);if(n < 0){perror("pipe");exit(1);}//创建紫禁城pid_t id = fork();if(id < 0){perror("fork");exit(1);}if(id == 0){if(!channels->empty()){//第二次之后创建的管道for(auto &channel : *channels){channel.CloseChannel();}}//childclose(pipefd[1]);dup2(pipefd[0],0);task();close(pipefd[0]);exit(0);}//父进程close(pipefd[0]);//构建名字std::string channel_name = "Channel  " + std::to_string(i);channels->push_back(Channel(pipefd[1],id,channel_name));//close(pipefd[1]);}
}int NextChannel(int channelnum)
{static int next = 0;int channel = next;next++;next %= channelnum;return channel;
}void SendTaskCommand(const Channel &channel,int taskcommand)
{size_t n = write(channel.Getfd(),&taskcommand,sizeof(taskcommand));if(n != sizeof(taskcommand)){perror("write");}
}void CtrlProcessOnce(std::vector<Channel> &channels)
{sleep(1);//选择任务int taskcommand = Select();//选择信道和进程int channel_index = NextChannel(channels.size());//发送任务SendTaskCommand(channels[channel_index],taskcommand);std::cout << "taskcommand:" << taskcommand << "  channel:"\<<channels[channel_index].GetName() << "  sub process:"\<< channels[channel_index].GetProcessId() << std::endl;
}//通过channel来控制紫禁城
void CtrlProcess(std::vector<Channel> &channels,int times = -1)
{if(times > 0){while(times--){CtrlProcessOnce(channels);}}else{while(true){CtrlProcessOnce(channels);}}
}//回收管道和子进程
void CleanUpChannels(std::vector<Channel> &channels)
{// for(auto &channel : channels)// {//     channel.CloseChannel();// }for(auto &channel : channels){channel.Wait();}
}// ./processpool 5
int main(int argc,char* argv[])
{if(argc!=2){std::cerr<<"Usage:"<<argv[0]<<"processnum"<<std::endl;return 1;}int num = std::stoi(argv[1]);LoadTask();std::vector<Channel> channels;//创建信道和子进程CreateChannelAndSub(&channels,num,work);//通过channel控制子进程CtrlProcess(channels,10);CleanUpChannels(channels);// for(auto &channel : channels)// {//     std::cout << " ---------------------- " <<std::endl;//     std::cout << channel.GetName() << std::endl;//     std::cout << channel.Getfd() << std::endl;//     std::cout << channel.GetProcessId() << std::endl;// }// sleep(100);return 0;
}

青春版Shell中添加管道实现

管道读写规则

当没有数据可读时

O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止

O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN

当管道满的时候

O_NONBLOCK disable: write调用阻塞,直到有进程读走数据

O_NONBLOCK enable:调用返回-1,errno值为EAGAIN

如果所有管道写端对应的文件描述符被关闭,则read返回0

如果所有管道读端对应的文件描述符被关闭,则write操作会产生信号SIGPIPE,进而可能导致write进程退出

当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性

当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性

管道特点 

只能用于具有共同祖先的进程(具有亲缘关系的进程)之间进行通信

一个管道由一个进程创建,然后该进程调用fork,此后父、子进程之间就可应用该管道

管道提供流式服务

进程退出,管道释放,所以管道的生命周期随进程

内核会对管道操作进行同步与互斥 管道是半双工的,数据只能向一个方向流动

需要双方通信时,需要建立起两个管道

命名管道

原理

有进程、磁盘上有文件,进程要打开对应的文件描述符表struct files_struct

里面包含数组struct file* fd_array[ ]

struct file里面要有属性集合和操作集合

通过文件内核级的缓冲区向磁盘文件中写数据

另一个进程要打同一文件,要有对应的PCB和文件描述符表,有相对应的文件对象,新文件的属性集操作集文件内核缓冲区都差不多,没必要再创建一份,操作系统不会做浪费时间浪费空间的事

至此两份进程可以看到同一文件了

怎么保证两个毫不相关的进程打开的是同一文件呢?

每一个文件都有文件路径(这个文件路径具有唯一性)

这就是命名管道,依旧是内存级别的进行通信的方案

文件需要是特殊文件,文件打开后不会将数据刷新到磁盘,而是在内存级别进行文件通信

通过路径标识保证唯一性的叫命名管道

代码

这是个接口,可以制作一个FIFO

使用呢是这样用:

mkfifo myfifo

 可以这样进行读写:

如果想让左侧的终端不断向右侧写入则可以:

while :;do sleep 1;echo "hello named pipe"; done >> myfifo

 

那怎样让我们写的进程实行代码级别的通信呢?

还得是这个库函数

 这是一个unlink:

可以删除指定目录下的文件

 这是两个接口:创建一个管道、移除一个管道

namedPiped.hpp:

#pragma once#include<iostream>
#include<sys/types.h>
#include<sys/stat.h>
#include<cerrno>
#include<cstdio>
#include<unistd.h>
#include<string>const std::string comm_path = "./myfifo";int CreateNamedPipe(const std::string &path)
{int res = mkfifo(path.c_str(),0666);if(res != 0){perror("mkfifo");}return res;
}int RemoveNamedPipe(const std::string &path)
{int res = unlink(path.c_str());if(res != 0){perror("unlink");}return res;
}

 用cpp对代码封装:

#pragma once#include<iostream>
#include<sys/types.h>
#include<sys/stat.h>
#include<cerrno>
#include<cstdio>
#include<unistd.h>
#include<string>const std::string comm_path = "./myfifo";class NamePiped
{
public:NamePiped(const std::string &path):_fifo_path(path){int res = mkfifo(path.c_str(),0666);if(res != 0){perror("mkfifo");}}~NamePiped(){int res = unlink(_fifo_path.c_str());if(res != 0){perror("unlink");}}
private:const std::string _fifo_path;
};

 相应的我们要对其进行身份的识别,是创建者才需要执行对应的操作:

#pragma once#include<iostream>
#include<sys/types.h>
#include<sys/stat.h>
#include<cerrno>
#include<cstdio>
#include<unistd.h>
#include<string>#define Creater 1
#define User 2const std::string comm_path = "./myfifo";class NamePiped
{
public:NamePiped(const std::string &path,int who):_fifo_path(path), _id(who){if(_id == Creater){int res = mkfifo(path.c_str(),0666);if(res != 0){perror("mkfifo");}}}~NamePiped(){if(_id == Creater){int res = unlink(_fifo_path.c_str());if(res != 0){perror("unlink");}}}
private:const std::string _fifo_path;int _id;
};

创建管道为了读写:

#pragma once#include<iostream>
#include<sys/types.h>
#include<sys/stat.h>
#include<cerrno>
#include<cstdio>
#include<unistd.h>
#include<string>
#include<fcntl.h>#define DefaultFd -1
#define Creater 1
#define User 2
#define Read O_RDONLY
#define Write O_WRONLYconst std::string comm_path = "./myfifo";class NamePiped
{
private://打开文件的模式bool OpenNamedPipe(int mode){_fd = open(_fifo_path.c_str(),mode);if(_fd < 0){return 0;}return true;}
public:NamePiped(const std::string &path,int who):_fifo_path(path), _id(who),_fd(DefaultFd){if(_id == Creater){int res = mkfifo(path.c_str(),0666);if(res != 0){perror("mkfifo");}}}bool OpenForRead(){return OpenNamedPipe(Read);}bool OpenForWrite(){return OpenNamedPipe(Write);}~NamePiped(){if(_id == Creater){int res = unlink(_fifo_path.c_str());if(res != 0){perror("unlink");}}if(_fd != DefaultFd){close(_fd);}}
private:const std::string _fifo_path;int _id;int _fd;
};

于是服务器端和客户端的调用方式也出来了

client.cc:

#include"namedPiped.hpp"int main()
{NamePiped fifo(comm_path,User);fifo.OpenForWrite();return 0;
}

server.cc:

#include"namedPiped.hpp"int main()
{NamePiped fifo(comm_path,Creater);fifo.OpenForRead();return 0;
}

还要有相应的读写管道的操作:

#pragma once#include<iostream>
#include<sys/types.h>
#include<sys/stat.h>
#include<cerrno>
#include<cstdio>
#include<unistd.h>
#include<string>
#include<fcntl.h>#define DefaultFd -1
#define Creater 1
#define User 2
#define Read O_RDONLY
#define Write O_WRONLY
#define BaseSize 4096const std::string comm_path = "./myfifo";class NamePiped
{
private://打开文件的模式bool OpenNamedPipe(int mode){_fd = open(_fifo_path.c_str(),mode);if(_fd < 0){return 0;}return true;}
public:NamePiped(const std::string &path,int who):_fifo_path(path), _id(who),_fd(DefaultFd){if(_id == Creater){int res = mkfifo(path.c_str(),0666);if(res != 0){perror("mkfifo");}}}bool OpenForRead(){return OpenNamedPipe(Read);}bool OpenForWrite(){return OpenNamedPipe(Write);}//输出:const &:const std::string &XXX//输入:*      std::string *//输入输出:&   std::string &int ReadNamedPipe(std::string *out){char buffer[BaseSize];int n = read(_fd,buffer,sizeof(buffer));if(n > 0){//读取成功buffer[n] = 0;*out = buffer;}return n;}int WriteNamedPipe(const std::string &in){return write(_fd,in.c_str(),in.size());}~NamePiped(){if(_id == Creater){int res = unlink(_fifo_path.c_str());if(res != 0){perror("unlink");}}if(_fd != DefaultFd){close(_fd);}}
private:const std::string _fifo_path;int _id;int _fd;
};

接下来就是实现服务器端和客户端进行通信:

client.cc:

#include"namedPiped.hpp"int main()
{NamePiped fifo(comm_path,User);if(fifo.OpenForWrite()){std::cout << "Please Enteer -> ";std::string message;std::getline(std::cin,message);     //从标准输入中获取信息到message中fifo.WriteNamedPipe(message);}return 0;
}

 server.cc:

#include"namedPiped.hpp"int main()
{NamePiped fifo(comm_path,Creater);if(fifo.OpenForRead()){while(true){std::string message;int n = fifo.ReadNamedPipe(&message);if(n > 0){std::cout << "Client Say " << message << std::endl;}}}return 0;
}

 

对于读端而言,如果我们打开文件,但是写端还没来,会阻塞在open调用中,直到对方打开

命名管道是通过文件路径让不同进程看到同一份资源的~

下篇说共享内存捏

这篇关于精彩管道不会梦到深沉蓝调的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1107578

相关文章

如何保证android程序进程不到万不得已的情况下,不会被结束

最近,做一个调用系统自带相机的那么一个功能,遇到的坑,在此记录一下。 设备:红米note4 问题起因 因为自定义的相机,很难满足客户的所有需要,比如:自拍杆的支持,优化方面等等。这些方面自定义的相机都不比系统自带的好,因为有些系统都是商家定制的,难免会出现一个奇葩的问题。比如:你在这款手机上运行,无任何问题,然而你换一款手机后,问题就出现了。 比如:小米的红米系列,你启用系统自带拍照功能后

看完这个不会配置 logback ,请你吃瓜!

之前在 日志?聊一聊slf4j吧 这篇文章中聊了下slf4j。本文也从实际的例子出发,针对logback的日志配置进行学习。 logack 简介 logback 官网:https://logback.qos.ch/ 目前还没有看过日志类框架的源码,仅限于如何使用。所以就不说那些“空话”了。最直观的认知是: logback和log4j是一个人写的springboot默认使用的日志框架是

在项目开发中,jsp页面不会少了,如何公用页面(添加页面和修改页面)和公用样式代码(css,js)?

在项目开发中,如何公用添加页面和修改页面? <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%><html><head><title>岗位设置</title><%@ include file="/WEB-INF/jsp/public/common.jspf"%></head><body> <!-- 标

Redis 管道的神奇力量

今天我们要来探索一个 Redis 中非常强大且实用的特性——管道(Pipeline)。如果你想让你的 Redis 操作更加高效,那么这篇文章绝对值得一读。 一、Redis 管道是什么 Redis 管道是一种在客户端和服务器之间批量执行命令的技术。它允许客户端将多个命令一次性发送到服务器,而不是逐个发送并等待每个命令的响应。服务器会按照顺序执行这些命令,并将所有命令的响应一次性返回给客户端。

【Linux】Linux 管道:进程间通信的利器

文章目录 Linux 管道:进程间通信的利器1. 什么是管道?2. 管道的分类2.1 匿名管道(Unnamed Pipe)2.2 命名管道(Named Pipe,FIFO) 3. 管道的局限性4. 结论 Linux 管道:进程间通信的利器 在 Linux 系统中,管道(Pipe)是进程间通信(IPC, Inter-Process Communication)的重要机制之一。

涉密电脑插U盘会不会被发现?如何禁止涉密电脑插U盘?30秒读懂!

在涉密电脑插U盘的那一瞬间,你是否也好奇会不会被发现?涉密电脑的安全监控可是滴水不漏的!想知道如何彻底禁止涉密电脑插U盘?简单几招搞定,轻松锁死外部设备,信息安全无懈可击! 涉密电脑插U盘会不会被发现? 涉密电脑是否会在插入U盘时被发现,需要根据具体情况来判断。在一些情况下,涉密电脑可能没有安装任何监控软件或安全工具,插入U盘可能不会立即触发警告。然而,随着信息安全管理的不断升级,越来越多

是谁还不会flink的checkpoint呀~

1、State Vs Checkpoint State:状态,是Flink中某一个Operator在某一个时刻的状态,如maxBy/sum,注意State存的是历史数据/状态,存在内存中。 Checkpoint:快照点, 是Flink中所有有状态的Operator在某一个时刻的State快照信息/存档信息 一句话概括: Checkpoint就是State的快照 目的:假设作业停止了,下次启动的

学不会去当产品吧?Flink实战任务调优

背景 在大数据领域我们都知道,开发是最简单,任务的合理调优、问题排查才是最重要的。 我们在之前的文章《Flink面试通关手册》中也讲解过,作者结合线上出现的一些问题,总结了一些任务调优需要注意的点。 一些简单的原则 我们在之前的文章《Flink面试通关手册》中提到过一个问题,Flink任务延迟高,想解决这个问题,你会如何入手? 当时我们给出的答案是: 在Flink的后台任务管理中,

数据湖解决方案关键一环,IceBerg会不会脱颖而出?

点击上方蓝色字体,选择“设为星标” 回复”资源“获取更多资源 小编在之前的详细讲解过关于数据湖的发展历程和现状,《我看好数据湖的未来,但不看好数据湖的现在》 ,在最后一部分中提到了当前数据湖的解决方案中,目前跳的最凶的三巨头包括:Delta、Apache Iceberg 和 Apache Hudi。 本文中将详细的介绍一下其中的IceBerg,看一下IceBerg会不会最终脱颖而出。 发展历

《挑战极限,畅享精彩 ——韩星地带:逃脱任务 3 震撼来袭》

在综艺的浩瀚星海中,总有那么一些节目如璀璨星辰般闪耀,而《韩星地带:逃脱任务 3》无疑就是其中的佼佼者。 2024 年,这个令人热血沸腾的真人秀节目再度回归,为观众带来一场惊心动魄的冒险之旅。节目由韩国 “国民 MC” 刘在石领衔主持,他那无与伦比的综艺感和控场能力,如同定海神针般,稳稳地把控着节目的节奏。权俞利,少女时代的魅力成员,勇敢与智慧并存,在节目中展现出令人惊叹的一面。新加入的金东炫