2

目前正在做两个分叉来管道两个进程,但我认为我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);  
4

2 回答 2

0

如果它只是一个有两个进程的管道,我根本不会等待。只需在父母和孩子中分叉并执行 exec 即可。

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);
}
于 2012-11-30T23:05:49.617 回答
0

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

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

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

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_FAILUREfrom <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);
于 2012-11-30T23:07:43.317 回答