当“读取”可以阻止管道中的父进程时,为什么要“等待”子进程?

Why `wait` for the child when `read` could supposedly block the parent process in pipe?

提问人:Overstacked 提问时间:10/13/2023 最后编辑:OkaOverstacked 更新时间:10/13/2023 访问量:63

问:

我正在学习进程之间的通信,我看到了以下代码,用于在父进程和子进程之间乒乓球一个字节:pipe

int
main(int argc, char **argv)
{
    int p[2];
    char buf[2];
    char *send = "a", *rec = "b";
    pipe(p);

    int pid = fork(); 
    if(pid == 0){

        if(read(p[0], buf, 1) != 1){
            fprintf(2, "child failed to read byte from parent.\n");
            exit(1);
        };
        close(p[0]);

        printf("%d: received ping\n",getpid());

        if(write(p[1], rec, 1) != 1){
            fprintf(2, "child failed to send byte to parent.\n");
            exit(1);
        };

        close(p[1]); 
        exit(0);

    } else if(pid > 0){
        
        if(write(p[1], send, 1) !=1){
            fprintf(2, "parent failed to send byte to child.\n");
            exit(1);
        };

        close(p[1]); 

        wait(0);
        
        if(read(p[0], buf, 1) != 1) { 
            fprintf(2, "parent failed to read byte back from child.\n");
            exit(1);
        };
        close(p[0]);

        printf("%d: received pong\n", getpid());

        exit(0);
    }
    else exit(1);
}

此代码有效。然而,在了解到这一点之后

如果没有可用的数据,则对管道的读取将等待写入数据或所有文件描述符 指要关闭的写入端;在后一种情况下,read 将返回 0,就像 已访问数据文件。

我开始有些怀疑。in 父进程现在似乎是多余的,因为在父进程写入之前,父进程不会运行,这在某种程度上充当了 .wait(0)readwait()

因此,我删除了该行,代码仍然可以打印“received pong”,但不再打印“received ping”,这意味着孩子没有按预期执行。这让我很困惑。wait(0)read

C 工艺 IPC 等待

评论


答:

1赞 Oka 10/13/2023 #1

澄清一下:父进程使用等待来等待任何子进程终止,并释放与之关联的系统信息(通常称为收获僵尸进程)。它的功能仅与写入/读取管道无关,因为它模糊地属于进程间通信的范畴。

如果没有父进程的 and,父进程很可能只是在子进程获得 CPU 时间之前读取它写入管道的字节。毕竟,这两个过程都是对同一管道的读取和写入。在这种情况下,父进程无法通过退出而不等待来正确获取子进程。子进程成为一个孤立进程,因为它将永远阻塞,试图从管道中读取一个字节,因为它仍然打开管道的写入端。waitwriteread

使用 present 时,父进程将一个字节写入管道,然后阻塞等待子进程终止。大约在同一时间,子进程读取一个字节(可能是阻塞),然后写入一个字节,然后终止。子进程终止后,父进程将收获子进程,然后读取一个字节。wait

在适当的情况下,将两根管道留在原处进行双向通信,并更积极地(即尽早)使用每根管道的未使用端。警惕僵局waitclose