news 2026/7/29 8:04:56

匿名管道--任务派发程序

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
匿名管道--任务派发程序

整体代码逻辑架构图如下:

整体架构图如下:

整体代码如下:

main.cc:

#include "processpool.hpp" #include "Tasks.hpp" int main(int argc, char *argv[]) { if(argc!=2){ cout<<"Usage: "<<argv[0]<<" <process_num>"<<endl; return -1; } int process_num = stoi(argv[1]); proc_pool *pool = new proc_pool(process_num, worker); //初始化进程池 pool->Initproc_pool(); //分发任务 pool->Dispatch_task(); sleep(3); //打印进城池 pool->Print(); //清空进程池 pool->Delete_proc_pool(); delete pool; return 0; }

processpool.hpp:

#ifndef PROCESSPOOL_HPP #define PROCESSPOOL_HPP #include <iostream> #include <vector> #include <functional> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <string> #include "Tasks.hpp" using namespace std; using work_t = function<void()>; // 定义函数指针类型 enum : int { OK, FORK_ERROR, PIPE_ERROR, READ_ERROR, WRITE_ERROR, EXIT_ERROR }; // 先描述 class channel { public: channel(int procfd, pid_t who) : _procfd(procfd), who(who) {} // 构造函数 ~channel() {} string Name() { return name = "channel_" + to_string(who) + "-" + to_string(_procfd); // 获取子进程名 } // 4个get函数 void send(int cmd) { ::write(_procfd, &cmd, sizeof(cmd)); // 发送命令 } bool Close() { if (_procfd < 0) return true; if (::close(_procfd) == -1) { perror("close"); return false; } _procfd = -1; // 文件描述符必定大于0,因此-1无效 return true; } pid_t Id() { return who; // 获取子进程id } int procid() { return _procfd; // 获取管道fd } private: int _procfd; string name; pid_t who; }; // 再组织 class proc_pool { public: proc_pool(int n, work_t work) : _work(work), proc_num(n) { } ~proc_pool() { } int Initproc_pool() { // 创建n个子进程 for (int i = 0; i < proc_num; ++i) { // 1.创建管道 int pipefd[2]; int n = pipe(pipefd); if (n < 0) { return PIPE_ERROR; // 管道创建失败 } // 2.创建父子进程 pid_t pid = fork(); if (pid < 0) { return FORK_ERROR; // 创建进程失败 } if (pid == 0) { // 子进程关闭历史fd for (auto &ch : _channels) { cout << "已关闭: _procfd=" << ch.procid() << endl; ch.Close(); } // 子进程关闭写端 ::close(pipefd[1]); cout << "子进程获取到读端fd: " << pipefd[0] << endl; // 子进程重定向标准输入为读端 dup2(pipefd[0], 0); // 子进程开始完成父进程分发的随机任务 worker(); // 子进程退出 _exit(OK); // 子进程退出 } // 3.父进程关闭读端,子进程关闭写端 ::close(pipefd[0]); // 4.父进程保存子进程id和管道fd _channels.emplace_back(pipefd[1], pid); } return OK; } void Dispatch_task() { int who = 0; int num = 20; while (num--) { // 1.选择一个任务 int taskcode = tasks.Task_select(); // 2.选择一个子进程管道 // 先给管道内部成员起别名,方便操作 channel &ch = _channels[who++ % proc_num]; sleep(1); cout << "父进程分发任务码:" << taskcode << ch.Name() << endl; cout << "任务还剩: " << num << " 个" << endl; // 3.发送任务码给子进程 ch.send(taskcode); } } void Delete_proc_pool() { // 删除管道 for (auto &ch : _channels) { bool ret=ch.Close();//close后,写端关闭,子进程读取到EOF,退出循环,退出子进程 pid_t pid = waitpid(ch.Id(), nullptr, 0); // 等待子进程退出 if(ret==true&&pid>0){ cout << "子进程退出成功,ID=" << pid << endl; } else{ cout << "子进程退出失败,ID=" << pid << endl; } } } void Print(){ for (auto &ch : _channels) { cout << "进程池元素正在循环打印中:" << ch.Name() << endl; } } private: vector<channel> _channels; work_t _work; int proc_num; }; #endif

Tasks.hpp:

#ifndef TASKS_HPP #define TASKS_HPP #include <iostream> #include <vector> #include <functional> #include <unistd.h> #include <sys/types.h> #include <ctime> using namespace std; using task_t=function<void()>; // 定义函数指针类型 class Tasks { public: Tasks() { srand(time(NULL)); task_queue.push_back([](){cout<<getpid()<<" :进程"<<"任务1"<<endl;}); task_queue.push_back([](){cout<<getpid()<<" :进程"<<"任务2"<<endl;}); task_queue.push_back([](){cout<<getpid()<<" :进程"<<"任务3"<<endl;}); task_queue.push_back([](){cout<<getpid()<<" :进程"<<"任务4"<<endl;}); } ~Tasks() {} //随机选择任务码 int Task_select(){ return rand()%task_queue.size(); } //执行vector函数队列中的任务 void Execute_task(unsigned long int num){ if(num < task_queue.size()||num<0) { task_queue[num](); } else { cout<<"任务码不存在"<<endl; } } private: vector<task_t> task_queue; }; //任务对象 Tasks tasks; //子进程进行完成任务 void worker(){ while (true) { int cmd=0; // 从管道读取任务码,直接拿pipefd是拿不到的,所以之前dup2重定向了标准输入,所以这里直接从标准输入读取 int n= read(0, &cmd, sizeof(cmd)); if(n == 0) { cout<<"子进程: "<<getpid()<<"读取到文件EOF"<<endl; break; // 读取失败,退出循环 } else { tasks.Execute_task(cmd); } } } #endif

Makefile:

SRC=$(wildcard *.cc) OBJ=$(SRC:.cc=.o) BIN=pipe $(BIN):$(OBJ) g++ -o $@ $^ %.o:%.cc g++ -c $< .PHONY:clean clean: rm -rf $(BIN) $(OBJ) .PHONY:test test: @echo $(SRC) @echo $(OBJ)
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/29 8:04:01

MANUS Metagloves Pro,让指尖动作精准走进数字世界

在元宇宙、人形机器人、数字孪生、虚拟仿真技术飞速迭代的当下&#xff0c;手部作为人体最灵活、最精细的交互载体&#xff0c;其数字化复刻能力直接决定了沉浸式交互、智能操控、数字内容创作的真实质感。传统动作捕捉设备受限于光学遮挡、数据漂移、精度不足等问题&#xff0…

作者头像 李华
网站建设 2026/7/29 8:03:58

第 02 课:变量、数据类型、运算与键盘输入

第 02 课&#xff1a;变量、数据类型、运算与键盘输入 本课目标 学完后&#xff0c;你应当能够&#xff1a; 用变量保存整数、小数、文字和真假状态。修改变量并完成基本运算。使用 Scanner 接收键盘输入。看懂常见的类型错误。 1. 用 IDEA 打开学习目录 打开 IDEA&#xff0c;…

作者头像 李华
网站建设 2026/7/29 8:03:46

Shell函数进阶:从基础语法到生产级脚本模块化实战

1. 从“命令堆叠”到“模块化”&#xff1a;为什么你需要掌握Shell函数如果你写过超过50行的Shell脚本&#xff0c;大概率经历过这样的场景&#xff1a;一段用来检查日志文件是否存在的代码&#xff0c;在脚本的开头、中间和结尾各出现了一次&#xff0c;每次只是改了个文件名。…

作者头像 李华
网站建设 2026/7/29 8:03:22

STM32 HAL库SysTick配置与应用:从心跳定时器到RTOS时基

1. 项目概述&#xff1a;为什么SysTick是STM32的“心跳”玩过STM32的朋友都知道&#xff0c;定时器是单片机的核心外设之一&#xff0c;从简单的延时到复杂的PWM输出都离不开它。但在众多定时器中&#xff0c;有一个非常特殊的存在——系统滴答定时器&#xff0c;也就是SysTick…

作者头像 李华
网站建设 2026/7/29 8:02:23

薄荷:穿越千年的清凉之味

初秋午后&#xff0c;指尖捻起一片薄荷叶&#xff0c;轻轻揉搓&#xff0c;那股清冽的凉意便从叶脉间迸发出来&#xff0c;直抵鼻腔。这味道里藏着风——不是温吞的南风&#xff0c;而是穿林打叶的山风&#xff1b;藏着时节——不是万物蛰伏的深冬&#xff0c;而是暑气未消却已…

作者头像 李华
网站建设 2026/7/29 8:02:10

Arduino为何二十年不倒?从生态、教育到效率工具的深度解析

1. 开源硬件领域的“常青树”&#xff1a;Arduino现象 在嵌入式开发和创客圈子里混了十几年&#xff0c;我见过无数技术平台和开发板如流星般划过天际&#xff0c;火一阵子就销声匿迹。但有一个名字&#xff0c;从2005年诞生至今&#xff0c;近二十年过去了&#xff0c;依然活跃…

作者头像 李华