两把叉子和等待的使用

时间:2012-11-30 22:49:58

标签: c unix

目前正在做两个forfor来管道两个进程,但我认为我的wait(&status)错了,因为在命令之后我的shell挂起并且没有返回到我的提示符。我知道我的管道工作正常,因为如果我删除等待,我可以看到结果。

任何提示?

pipe(mypipe);
pid1=fork();
if(pid1==0)
{       
    pid2=fork();
    if(pid2==0)
    {
        close(0);
        dup(mypipe[0]);
        close(mypipe[1]);
        execv(foundnode2->path_dir,arv2);
        exit(0);
    }
    close(1);
    dup(mypipe[1]);
    close(mypipe[0]);
    pid2 = wait(&status2);
    execv(foundnode1->path_dir,arv1);
    exit(0);
}
pid1 = wait(&status2);  

2 个答案:

答案 0 :(得分:0)

如果它只是一个有两个进程的管道,我就不会等了。只需在父母和孩子中分叉并做一个执行。

int fd[2];
pipe(fd);
int pid = fork();
if (pid == -1) {
    /* error handling */
} else if (pid == 0) {
    dup2(fd[0], 0);
    close(fd[1]);
    execv(foundnode2->path_dir,arv2);
    /* error handling for failed exec */
    exit(1);
} else {
    dup2(fd[1], 1);
    close(fd[0]);
    execv(foundnode1->path_dir,arv1);
    /* error handling for failed exec */
    exit(1);
}

答案 1 :(得分:0)

经验法则:如果您使用dup()dup2()将管道的一端映射到标准输入或标准输出,则应close()管道本身的两端。你不是那样做的;你的等待等待程序完成,但程序将无法完成,因为仍有一个管道打开的程序可以写入管道。此外,创建管道的过程需要关闭管道的两端,因为它本身不使用管道(子进程正在使用它)。另请参阅C MiniShell — Adding Pipelines

此外,您不应该等到第一个孩子在启动第二个孩子之前完成(因此pid2 = wait(&status2);行是个坏主意)。管道容量相当小;如果要传输的总数据太大,写作孩子可能会阻止等待阅读孩子阅读,但是阅读孩子还没有开始,因为它正在等待写作孩子退出(并且需要很长时间为了解决这个问题的僵局)。您看到输出没有wait()调用,因为管道的第二部分执行并处理来自管道的第一部分的数据,但它仍在等待来自shell的更多数据。 / p>

考虑到这些提示,您最终可能会:

pipe(mypipe);
pid1 = fork();
if (pid1 == 0)
{        
    pid2 = fork();
    if (pid2 == 0)
    {
        close(0);
        dup(mypipe[0]);
        close(mypipe[1]);
        close(mypipe[0]);
        execv(foundnode2->path_dir, arv2);
        fprintf(stderr, "Failed to exec %s\n", foundnode2->path_dir);
        exit(1);
    }
    close(1);
    dup(mypipe[1]);
    close(mypipe[0]);
    close(mypipe[1]);
    execv(foundnode1->path_dir, arv1);
    fprintf(stderr, "Failed to exec %s\n", foundnode1->path_dir);
    exit(1);
}
close(mypipe[0]);
close(mypipe[1]);
pid1 = wait(&status1);

当命令失败到execv()时,请注意错误报告给标准错误。此外,退出状态0应保留为成功; 1是方便的错误退出状态,或者您可以使用EXIT_FAILURE中的<stdlib.h>

还有很多错误检查遗漏了; fork()操作可能会失败; pipe()可能会失败。结果是,如果第二个fork()失败,您仍然会启动第二个孩子(由foundnode1->path_dir标识)。

我注意到你可以通过将管道创建移动到第一个子进程中来节省一些工作(父进程不需要 - 实际上,不能 - 关闭管道):

int pid1 = fork();
if (pid1 == 0)
{
    int mypipe[2];      
    pipe(mypipe);
    int pid2 = fork();
    if (pid2 == 0)
    {
        close(0);
        dup(mypipe[0]);
        close(mypipe[1]);
        close(mypipe[0]);
        execv(foundnode2->path_dir, arv2);
        fprintf(stderr, "Failed to exec %s\n", foundnode2->path_dir);
        exit(1);
    }
    close(1);
    dup(mypipe[1]);
    close(mypipe[0]);
    close(mypipe[1]);
    execv(foundnode1->path_dir, arv1);
    fprintf(stderr, "Failed to exec %s\n", foundnode1->path_dir);
    exit(1);
}
pid1 = wait(&status1);