在讲匿名管道之前我们必须要了解的前提知识我们知道在linux中进程都是独立了说明我们要将进程联系起来还是比较难的也就是说进程间要通信我们必须要让它们看到同一份资源。也就是说通信的前提就是让不同的进程看到同一份资源而匿名管道就是其中的一种方式。让进程看到同一份资源的方法进程间通信分类基于文件系统的方法匿名管道pipe命名管道System VIPC的方法 //system V的方法只适用于本地通信System V消息队列System V共享内存 //后续会讲这种方法的实现以及原理System V信号量POSIX IPC // 可以跨主机通信消息队列共享内存信号量互斥量条件变量读写锁匿名管道的概念管道是Unix中最古老的进程间通信的形式。我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”本质就是通过函数pipe来创建管道然后通过fork创建子进程来实现有血缘关系的进程之间的通信。#include unistd.h功能:创建一无名管道原型int pipe(int fd[2]);过程如下图1.父进程通过pipe()创建管道管道的读写特征1.读快写曼则read函数会阻塞2.读慢写快则write会阻塞3.读端关闭操作系统会发送信号立即停止写端继续写入因为确实没有意义4.写端关闭读端会将管道内容读完后结束。管道自身特点1.只能用于具有共同祖先的进程具有亲缘关系的进程之间进行通信通常一个管道由一个进程创建然后该进程调用fork此后父、子进程之间就可应用该管道。2.管道提供流式服务3.一般而言进程退出管道释放所以管道的生命周期随进程4.一般而言内核会对管道操作进行同步与互斥后续信号会讲5.管道是半双工的数据只能向一个方向流动需要双方通信时需要建立起两个管道匿名管道实战下面我们通过匿名管道来实现一个简单的进程池。这个代码会比较长不过做了充分的代码解释希望可以帮助你们理解匿名管道的用处。#include iostream #include cstdio #include sys/types.h #include sys/wait.h #include unistd.h #include cassert #include vector #include time.h #include cstdlib #include ctime using namespace std; #define PROCESSNUM 5 // 进程池中的子进程数量 #define MakeSeed() srand((unsigned long)time(NULL) ^ getpid()); //定义宏函数来设置随机种子 class proep //将管道和子进程作为一个整体进行分装 { public: proep(int writefd, int fd) : writefd_(writefd), fd_(fd) { char namebuffer[1024]; snprintf(namebuffer, sizeof(namebuffer) - 1, process-%d[pid(%d)-fd(%d)]\n, cnt, fd_, writefd_); name_ namebuffer; } public: static int cnt; //所有子进程完成任务个数的统计 string name_; //给这个整体一个名称名称里面包含了这是第几个任务以及这个任务是哪个进程完成的pid和这个整体的写端 int writefd_; //写端fd pid_t fd_; //子进程的文件描述符 }; int proep::cnt 1; //初始化任务数 typedef void (*func)(); //定义一个函数指针方便后续建立函数表任务表 //#####################让进程模拟完成不同的任务################################### void load_task() { cout 正在下载中。。。 endl; sleep(1); } void io_task() { cout 正在io中。。。 endl; sleep(1); } void delete_task() { cout 正在删除中。。。 endl; sleep(1); } //##############################任务列表结束######################################## //将任务函数加载到任务列表中 void LoadAllTask(vectorfunc task_list) { task_list.push_back(load_task); task_list.push_back(io_task); task_list.push_back(delete_task); } //父进程发送指定的任务给指定的进程 void seekTask(proep subpro, int taskindex) { cout seed tasknum: taskindex seed to subpro.name_; int n write(subpro.writefd_, taskindex, sizeof(taskindex)); assert(n sizeof(int)); (void)n; } //子进程接收任务函数 int receTask(int fd) { int ret 0; int n read(fd, ret, 4); if (n 4) return ret; else if (n 0) return -1; else { cerr 读取任务码错误 endl; return -2; } } //fork创建子进程 void createsubs(vectorproep *subs, const vectorfunc task_list) { for (int i 0; i PROCESSNUM; i) { int fds[2]; int n pipe(fds); assert(n 0); (void)n; int id fork(); if (id 0) { // 子进程关闭写端 close(fds[1]); // 子进程完成自己的任务 while (1) { //获取任务 int commotCode receTask(fds[0]); if (commotCode 0 commotCode task_list.size()) { task_list[commotCode](); } else if (commotCode -1) //写端关闭receTask函数返回-1表示读到0子进程退出 { break; } } // 子进程完成任务后退出 exit(1); } // 父进程关闭读端 close(fds[0]); //创建子进程和对应的管道subs数组添加这个整体 proep tmp(fds[1], id); subs-push_back(tmp); } } //父进程负载平衡的给子进程发送任务 void taskblancecontrol(vectorproep subs,const vectorfunc task_list,int num) { bool forever (num-1 ? true:false); while (1) { // 选择进程 int subindex rand() % PROCESSNUM; // 选择任务 int taskindex rand() % task_list.size(); seekTask(subs[subindex], taskindex); sleep(1); if(!forever) { num--; if(num 0) break; } } //完成指定的任务数后关闭所有管道的写端读端读到0后对应的子进程会退出 for(int i 0; i subs.size(); i) { close(subs[i].writefd_); } } //阻塞等待子进程退出 void waitprocess(vectorproep subs) { for(int i0;isubs.size();i) { waitpid(subs[i].fd_,NULL,0); } } int main() { // 设置随机种子 MakeSeed(); // 加载任务表 vectorfunc task_list; LoadAllTask(task_list); // 创建子进程将管道写端和子进程作为一个整体放进类proep中 vectorproep subs; createsubs(subs, task_list); // 父进程控制子进程完成任务 int num 5; taskblancecontrol(subs,task_list,num); //回收子进程 waitprocess(subs); return 0; }关于匿名管道讲到这里就结束啦对应命名管道感兴趣的可以看我的另一篇文章哦当然另一篇有了这篇文章的基础我就没有写得很详细啦https://blog.csdn.net/Su_han_dg/article/details/159115448?fromshareblogdetailsharetypeblogdetailsharerId159115448sharereferPCsharesourceSu_han_dgsharefromfrom_link