首页 > 解决方案 > C pipe fork fd 题 - 简单的 xv6 乒乓球题

问题描述

C新手在这里。我正在尝试在 xv6 中编写一个使用管道、叉子和文件描述符的简单程序。

int
main(int argc, char *argv[])
{
    int p[2];  // file descriptors for pipe
    char recv_buf[5];

    pipe(p);

    if (fork() == 0) {  // child
        read(p[0], recv_buf, 5);
        printf("%d: received %s\n", getpid(), recv_buf);
        close(p[0]);

        write(p[1], "pong", 5);
        close(p[1]);

    } else {  // parent
        write(p[1], "ping", 5);
        close(p[1]);

        read(p[0], recv_buf, 5);
        printf("%d: received %s\n", getpid(), recv_buf);
        close(p[0]);
    }
    exit(0);
}

我以为程序会成功打印

$ ./pingpong
$ "3: received ping" 
$ "4: received pong"

到终端输出。

相反,输出结果为:

$ ./pingpong
$ "3: received ping" 

谁能解释这里发生了什么?我认为每个进程都有自己的文件描述符副本,并且读/写会挂起父进程,直到管道的另一端有输出。那么为什么子进程没有收到“pong”调用呢?

请注意,如果我在父级中添加 wait(0) ,问题就会消失。

int
main(int argc, char *argv[])
{
    int p[2];  // file descriptors for pipe
    char recv_buf[5];

    pipe(p);

    if (fork() == 0) {  // child
        read(p[0], recv_buf, 5);
        printf("%d: received %s\n", getpid(), recv_buf);
        close(p[0]);

        write(p[1], "pong", 5);
        close(p[1]);

    } else {  // parent
        write(p[1], "ping", 5);
        wait(0); // this fixes the problem.  but why?
        close(p[1]);

        read(p[0], recv_buf, 5);
        printf("%d: received %s\n", getpid(), recv_buf);
        close(p[0]);
    }
    exit(0);
}
$ ./pingpong
$ "3: received ping" 
$ "4: received pong"

谁能解释为什么 wait(0) 导致程序成功?

标签: cxv6

解决方案


实际上,我在键入此内容后不久就找到了答案。

第一个程序的程序是在父块内我正在写入输出文件描述符,然后立即从输入文件描述符读取,这意味着父进程不会挂起。

结果是父进程在子进程能够进行任何读/写之前退出。

    if (fork() == 0) {  // child process never reached
        read(p[0], recv_buf, 5);
        printf("%d: received %s\n", getpid(), recv_buf);
        close(p[0]);

        write(p[1], "pong", 5);
        close(p[1]);

    } else {  // parent
        write(p[1], "ping", 5); // write to output fd
        close(p[1]); // close output fd

        read(p[0], recv_buf, 5); // read "ping" from input fd
        printf("%d: received %s\n", getpid(), recv_buf); // print "ping"
        close(p[0]); // close input fd
    }
    exit(0); // parent process exists immediately

wait(0) 通过允许子进程在父进程到达读取块之前读取/写入来解决此问题


推荐阅读