首页 文章

使用带有多个子进程的execl

提问于
浏览
5

我正在尝试创建一个创建多个子进程的进程,每个进程都调用file()函数 .

这是我到目前为止:

  • 父级将文件列表写入管道

  • 子进程将管道重定向到stdin并将stdout重定向到另一个管道并且每个管道都重定向 exec file .

  • 父级使用 select 等待终止子进程,并从相关管道(包含文件函数的输出)读取 .

当我只使用一个子进程时,一切都运行良好:子进程终止管道中的所有输出,并且父进程读取它 . 但是,当我使用2个子进程时,它们不会终止;文件功能进入“休眠”模式,等待更多输入 . 然后父母也被阻止,等待孩子们终止 .

我已经创建了两个管道版本的最小包含示例:

#define NUM_CHILDREN (2)
//pipes from parent to children
int pipeP2C[NUM_CHILDREN][2];
//pipes from children to parent
int pipeC2P[NUM_CHILDREN][2];

int children_ids[NUM_CHILDREN];

int main()
{
//create pipes from parent to children and vice versa
for (int i = 0; i < NUM_CHILDREN; ++i){
    pipe(pipeP2C[i]);
    pipe(pipeC2P[i]);
}

//create first child
//Create initial g_parLevel child processes
pid_t pid;
int numForks = 0;
do
{
    pid = fork();
    // Parent process should count how many children it has
    if (pid > 0) {
        children_ids[numForks] = pid;
        ++numForks;
    }
    //child process also writes its' own pid to children_ids.
    else {
        children_ids[numForks] = (int)getpid();
    }
}
//Call fork again from parent process, if it doesn't have g_parLevel children already.
while (pid > 0 && numForks < NUM_CHILDREN);

//Now we have NUM_CHILDREN child processes, their ids are kept in the parent process, and each
//of them has (at least) it's own id kept in the suitable index in children_ids.

//parent - write to the children
if (pid > 0){
    //Iterate over all children
    for (int i = 0; i < NUM_CHILDREN; ++i)
    {
        std::string str = "/bin/ls";
        //close reading end
        close(pipeP2C[i][0]);
        //write to child
        write(pipeP2C[i][1], str.c_str(), (int)str.length());
        close(pipeP2C[i][1]);
    }

    //wait for the children to terminate
    int terminatedChildren = 0;
    while (terminatedChildren < NUM_CHILDREN)
    {
        int status;
        int terminatedChild = wait(&status);
        ++terminatedChildren;

        //read from the terminated child
        int childIndex = children_ids[0] == terminatedChild ? 0 : 1;

        //close writing end
        close(pipeC2P[childIndex][1]);
        char buf[2048];
        read(pipeC2P[childIndex][0], buf, sizeof(buf));
        close(pipeC2P[childIndex][0]);
        std::cerr<<"output from child "<<childIndex<<" is:\n"<<buf<<std::endl;
    }
}

//child process
if (pid == 0)
{
    //find the pipe to read from.
    int childPid = getpid();
    int childIndex = children_ids[0] == childPid ? 0 : 1;
    std::cerr<<"in child "<<childPid<<" index "<<childIndex<<std::endl;
    //wait until the parent has written data
    fd_set rfds;
    int ready;
    while(true)
    {
        FD_ZERO(&rfds);
        //we are interested in the reading end
        FD_SET(pipeP2C[childIndex][0], &rfds);
        ready = select(pipeP2C[childIndex][0] + 1, &rfds, NULL, NULL, NULL);
        if (ready > 0){
            std::cerr<<"ready"<<std::endl;

            //close the relevant writing end of the pipe from parent to child
            close(pipeP2C[childIndex][1]);
            //redirect input to stdin
            dup2(pipeP2C[childIndex][0], 0);
            close(pipeP2C[childIndex][0]);

            //close relevant reading end of the pipe from child to parent
            close(pipeC2P[childIndex][0]);
            //redirect output from stdout
            dup2(pipeC2P[childIndex][1], 1);
            close(pipeC2P[childIndex][1]);

            execl("/usr/bin/file","file", "-n", "-f", "-", (char *)NULL);

            //should never get here
            std::cerr<<"file failed"<<std::endl;
            exit(1);
        }
    }
}
}

为什么不等

1 回答

  • 1

    您没有关闭其他进程的文件描述符 . 当您 fork 您的孩子仍然引用其他孩子的文件描述符 .

    在处理之前关闭它们 . 就像是:

    for(int k=0;k<NUM_CHILDREN;k++){
        if(k!=childIndex){
            close(pipeP2C[k][0]);
            close(pipeP2C[k][1]);
            close(pipeC2P[k][0]);
            close(pipeC2P[k][1]);
        }
    }
    

    在子部分的 while(true) 位之上应该可以解决问题 . 所以:

    //child process
    if (pid == 0)
    {
        //find the pipe to read from.
        int childPid = getpid();
        int childIndex = children_ids[0] == childPid ? 0 : 1;
        std::cerr<<"in child "<<childPid<<" index "<<childIndex<<std::endl;
        //wait until the parent has written data
        fd_set rfds;
        int ready;
        for(int k=0;k<NUM_CHILDREN;k++){
            if(k!=childIndex){
                close(pipeP2C[k][0]);
                close(pipeP2C[k][1]);
                close(pipeC2P[k][0]);
                close(pipeC2P[k][1]);
            }
        }
        while(true)
        {
            FD_ZERO(&rfds);
            //we are interested in the reading end
            FD_SET(pipeP2C[childIndex][0], &rfds);
            ready = select(pipeP2C[childIndex][0] + 1, &rfds, NULL, NULL, NULL);
            if (ready > 0){
                std::cerr<<"ready"<<std::endl;
    
                //close the relevant writing end of the pipe from parent to child
                close(pipeP2C[childIndex][1]);
                //redirect input to stdin
                dup2(pipeP2C[childIndex][0], 0);
                close(pipeP2C[childIndex][0]);
    
                //close relevant reading end of the pipe from child to parent
                close(pipeC2P[childIndex][0]);
                //redirect output from stdout
                dup2(pipeC2P[childIndex][1], 1);
                close(pipeC2P[childIndex][1]);
    
                execl("/usr/bin/file","file", "-n", "-f", "-", (char *)NULL);
    
                //should never get here
                std::cerr<<"file failed"<<std::endl;
                exit(1);
            }
        }
    }
    

相关问题