进程向系统申请资源存在一定的效率问题。系统调用在底层是有成本的。频繁的向操作系统申请资源会造成一定的开销。解决办法是一次性向系统申请你需要的资源,将这些资源在用户层管理维护起来,减少程序频繁的陷入内核。这就是池化的意思,可以简单的理解层,一次性申请全部的资源,然后将这些资源在用户层管理维护,需要使用时不再陷入内核。
#include<iostream>
#include<unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include<vector>
#include<string>
#include<stdio.h>
#include <stdlib.h>
#include"Task.hpp"#define Tasknum 2//输入 const &
//输出 *
//输入输出 &using namespace std;//子进程的pid,管道的writefdstruct channel
{pid_t _pid;int _child_fd;string _name;channel():_pid(-1),_child_fd(-1),_name(""){}channel(pid_t pid,int fd,const string& name):_pid(pid),_child_fd(fd),_name(name){}
};
void mission(int read_fd)
{sleep(5);cout<<"process run...\n"<<endl;cout<<"child::read_fd:"<<read_fd<<endl<<endl;int cnt=5;while(cnt--){ int task_id=0;int n=read(read_fd,&task_id,sizeof(int));if(n==0) //没有读取到就为0{cout<<"没有数据\n"<<endl;close(read_fd);exit(0);}cout<<"child:: read task_id--------"<<task_id<<endl;}return ;
}void Init_ProcessPool(vector<channel>& pool)
{//创建子进程建立管道for(int i=0;i<Tasknum;i++){ int pipefd[2];int ret = pipe(pipefd);if(ret==-1){cout<<"main:: pipe error ...\n"<<endl;exit(-2);}pid_t pid=fork();if(pid<0){cout<<"main:fork() error...\n"<<endl;exit(-1);}//建立管道//子进程执行if(pid==0){cout<<"child:: "<<getpid()<<" 关闭写端\n"<<endl;close(pipefd[1]);//子进程关闭写端//dup2(pipefd[0],0);cout<<"child::执行任务\n"<<endl;mission(pipefd[0]);cout<<"child::进程退出\n"<<endl;exit(0);}close(pipefd[0]);//父进程关闭读端sleep(1);string name="process-"+to_string(i);cout<<"main::组织子进程\n"<<endl;pool.push_back(channel(pid,pipefd[1],name));//将子进程的管道写端,pid,name组织cout<<pool.back()._name<<endl;}
}int main()
{time_t t;srand(time(&t));vector<channel> pool;//组织子进程Init_ProcessPool(pool);for(int i=0;i<Tasknum;i++){cout<<pool[i]._pid<<"---"<<pool[i]._child_fd<<"---"<<pool[i]._name<<endl;}//控制进程sleep(2);int cnt=5;while(cnt--){int task_id=rand()%Tasknum;//选择任务int process_id=rand()%Tasknum;//选择进程 //这里是随机选择,也可以轮询选择,cnt++%sizecout<<task_id<<endl;cout<<process_id<<endl;cout<<"main:: 选择子进程 "<<pool[process_id]._name<<" 任务码 "<<task_id<<endl;int n=write(pool[process_id]._child_fd,&task_id,sizeof(task_id));//将任务码传递给进程if(n<0){cout<<"main::write to "<<pool[process_id]._child_fd<<" false\n"<<endl;}sleep(1);}for(int i=0;i<Tasknum;i++){waitpid(-1,NULL,0);}// int child_ret=0;// int n=waitpid(-1,&child_ret,0);// if(n>0)// {// cout<<"wait sucessfully:: "<<n<<endl;// }return 0;
}
父进程第一次申请读写端文件描述符是3,4,fork后,子进程关闭4,子进程的task_struct中复制此时打开的内存级文件指针。父进程关闭读,在父进程的taskstruct中同步关闭相应的文件。
循环式的创建管道,子进程读端的fd值一样,但是指向的文件不一样。
管道应该在fork()之前创建。
父进程创建管道,他的写端也会被其他子进程拷贝,管道文件的写段也会被其他进程接收。
这影响父进程等待回收子进程的过程。需要先在中主进程依次关闭写端,再依次等待子进程。否则子进程会因为由于管道文件未关闭而阻塞等待,父进程也会阻塞等待子进程退出。导致程序宕机。
程序在最后wait时宕机。
或者在父进程中创建一个数组记录上一次打开的读端fd,子进程关闭所有的读端。