我正在学习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);
}

这个代码起作用了.然而,在了解到这一点后,

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

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

所以,我go 掉了wait(0)行,代码仍然可以打印"Receied Pong"but no more "received ping",这意味着子元素没有按照预期执行read.这让我很困惑.

推荐答案

澄清一下:父进程使用wait来等待任何子进程进入terminate,并释放与其相关的系统信息(通常称为reapinga zombie process).它的功能与对管道的写入/读取只有切线关系,因为它隐约属于进程间通信的范畴.

在父进程的writeread之间没有wait,很可能父进程将简单地读取它已经写入管道before的字节.子进程甚至获得CPU时间.毕竟,这两个进程都在对same管道进行读写.在这种情况下,父进程无法通过不等待而退出来正确地将子进程reap.子进程变为orphan process,因为它将永远阻塞,try 从管道中读取一个字节,因为它仍然打开管道的写入端.

如果存在wait,则父进程向管道写入一个字节,然后阻塞,以待子进程终止.大约在同一时间,子进程读取一个字节(可能是阻塞的),然后写入一个字节,然后终止.子进程终止后,父进程reaps将子进程,然后读取一个字节.

在适当的情况下,将wait留在原处,或者使用two pipes进行双向通信,并使用close来更积极地(即,尽可能早地)使用每一端的未使用端.对deadlocks保持警惕.

C++相关问答推荐

初始化char数组-用于初始化数组的字符串是否除了存储数组的位置之外单独存储在内存中

为什么下面的C代码会进入无限循环?

sizeof结果是否依赖于字符串的声明?

如何使用Python C API实现多线程程序?

由Go调用E.C.引起的内存快速增长

如何将已分配的数组(运行时已知的大小)放入 struct 中?

从组播组地址了解收到的数据包长度

为什么GCC可以调用未定义的函数?

fwrite无法写入满(非常大)缓冲区

如何在c++中包装返回空*的函数

在我的代码中,我需要在哪里编写输出函数?

是什么让numpy.sum比优化的(自动矢量化的)C循环更快?

Cairo STM32MP1 cairo_Surface_WRITE_TO_PNG始终返回CAROLIO_STATUS_WRITE_ERROR

用C++构建和使用DLL的困惑

用C++高效解析HTTP请求的方法

如何打印循环调度问题的时间表

c如何传递对 struct 数组的引用,而不是设置 struct 的副本

C 程序不显示任何输出,但它接受 CS50 Lab1 的输入问题

如何修复数组数据与列标题未对齐的问题?

C语言程序流程解释