石景山周边网站建设,台州做网站哪家好,网页设计师考试报名,北京造价员变更在哪个网站做#x1f4df;作者主页#xff1a;慢热的陕西人 #x1f334;专栏链接#xff1a;Linux #x1f4e3;欢迎各位大佬#x1f44d;点赞#x1f525;关注#x1f693;收藏#xff0c;#x1f349;留言 本博客主要内容管道后续的完善#xff0c;以及解决管道继承多个文件描… 作者主页慢热的陕西人 专栏链接Linux 欢迎各位大佬点赞关注收藏留言 本博客主要内容管道后续的完善以及解决管道继承多个文件描述符的问题 文章目录 1.管道程序的再优化1.1void ctrlprocess函数1.2EndPoint类1.3RecailmTask函数1.4子进程继承父进程文件描述符问题的解决 1.管道程序的再优化
1.1void ctrlprocess函数 分三步 确定任务确定执行任务的子进程.轮询式的执行任务 void ctrlprocess(const vectorEndPoint end_points)
{// 2.写成自动化也可以搞成交互式的int cnt 0;while (true){//1.确定任务int command ShowBoard();if(command 3) break;if(command 0 || command 2) continue;//2.确定执行任务的子进程.轮询式的int child cnt;cnt % end_points.size();cout 选择了进程 end_points[child].name() | 处理任务 command endl;//3.执行任务write(end_points[child]._write_fd, command, sizeof(command));sleep(1);}
}1.2EndPoint类 增加static成员number用于统计子进程个数增加string processname用于存储进程的名字增加name函数用于打印子进程的名字 // 先描述
class EndPoint
{
private:static int number;
public:pid_t _child; // 子进程pidint _write_fd; // 对应的文件描述符string processname;
public:// 构造EndPoint(int id, int fd): _child(id), _write_fd(fd){char namebuffer[64];snprintf(namebuffer, sizeof(namebuffer), process-%d[%d:%d], number, id, fd);processname namebuffer;}string name() const {return processname;}// 析构~EndPoint(){}
};1.3RecailmTask函数 用于子进程的回收 ①关闭写描述符根据前面讲的父进程关闭了管道对应的写描述符之后子进程也就退出了②回收子进程waitpid对应的函数进行回收 方案一两种操作分开执行
void RecailmTask(const vectorEndPoint end_points)
{//1.关闭写描述符for(int i 0; i end_points.size(); i) close(end_points[i]._write_fd);cout 父进程让所有的进程退出了 endl;sleep(5);//2.回收子进程for(int i 0; i end_points.size(); i) waitpid(end_points[i]._child, nullptr, 0);sleep(5);
}运行结果
子进程在父进程的操控下正常退出了 1.4子进程继承父进程文件描述符问题的解决
但是当我们把这两个过程合并的时候问题出现了
然后就卡住了
void RecailmTask(const vectorEndPoint end_points)
{//1.关闭写描述符for(int i 0; i end_points.size(); i) {close(end_points[i]._write_fd);waitpid(end_points[i]._child, nullptr, 0);}cout 父进程让所有的进程退出了 endl;sleep(5);
}这是为什么呢其实我们想一想父进程在创建子进程的时候子进程也会把父进程的文件描述符也会拷贝一份 所以除了第一个子进程当我们父进程关闭对应的写端的时候子进程不会关闭原因是其他的子进程也继承了对应的写端的文件描述符。所以写端并没有完全关闭所以这时候父进程去等待回收子进程的时候就会一直在等待造成了程序卡住的状态那么我们怎么解决呢
方案一反着顺序关闭写端
void RecailmTask(const vectorEndPoint end_points)
{//1.关闭写描述符for(int end end_points.size() - 1; end 0; --end) {close(end_points[end]._write_fd);waitpid(end_points[end]._child, nullptr, 0);}cout 父进程让所有的进程退出了 endl;sleep(5);
}可是我们这种办法只是解决了表象我们没有解决的根本的情况我们只是让程序可以正常的关闭但是子进程的那种继承父进程管道的文件描述符的问题还是没有解决并且这也是有一定不安全的情况在里面的因为管道不是一对一的情况了变成了多对一的情况可能会造成其他的子进程向其他管道中错误写入的问题
所以我们我解决这个问题这个问题我们应该在创建子进程管道的时候就解决好
思路我们每创建一个子进程把其对应的文件描述符存储在一个vector内部然后再创建第二个子进程的时候遍历vector的时候将他们依次关掉即可
void creatProcesses(vectorEndPoint end_points)
{//用于存储文件描述符vectorintfds;// 1.先进行构建控制结构,父进程写子进程读for (int i 0; i gnum; i){// 1.1创建管道int pipefd[2] {0};int ret pipe(pipefd);assert(ret 0); // 0正常 -1不正常(void)ret;// 1.2创建进程pid_t id fork();assert(id ! -1);if (id 0){//关闭不必要的描述符for(auto fd : fds) close(fd);// 子进程// 1.3关闭不要的fdclose(pipefd[1]);// 我们期望所有的子进程读取“指令”的时候都从标准输入读取// 1.3.1所以我们进行输入重定向dup2(pipefd[0], 0);// 1.3.2子进程开始等待获取命令WaitCommend();close(pipefd[0]);exit(0);}// 父进程// 1.3关闭不要的fdclose(pipefd[0]);// 1.4将新的子进程和他的管道写端构建对象。end_points.push_back(EndPoint(id, pipefd[1]));fds.push_back(pipefd[1]);}
}运行结果 到这本篇博客的内容就到此结束了。 如果觉得本篇博客内容对你有所帮助的话可以点赞收藏顺便关注一下 如果文章内容有错误欢迎在评论区指正