子进程死亡后,父进程不会从FIFO中读取

问题描述

所以。我必须从命名管道读取和写入,并且我尝试通过执行以下操作来完成此操作:父进程将命令写入FIFO,然后等待孩子死亡。子进程读取命令,然后在另一个FIFO中写入内容。父Parent从另一个FIFO读取消息并打印结果。我被限制使用fopen,因为在我的代码中,我在其他地方使用unisted的open,因此我没有nonblock标志。我将在下面附上摘要。另外,如果我在子进程上使用“ w”标志,则代码将完全冻结。我知道FIFO是一种阻止通讯的方式,但我不明白为什么我的父母无法阅读。预先感谢。

int main()
{
    FILE *fp1;
    FILE* fp2;
    unlink(FIFO_NAME1);
    unlink(FIFO_NAME2);
    //FIFO_NAME[1|2] is a macro containing the FIFO path
    if(mkfifo(FIFO_NAME1,0666) == -1)
    {
        printf("Something went wrong");
        return -1;
    }
    if(mkfifo(FIFO_NAME2,0666) == -1)
    {
        printf("Something went wrong");
        return -1;
    }
    while(1)
    {
        char command[MAX_SIZE];
        pid_t pid;
        if((pid=fork()) !=0)
        {
            //parent
                fgets(command,MAX_SIZE,stdin);

                if((fp1= fopen(FIFO_NAME1,"w")) == NULL)
                {
                    printf("Error");
                }
                fprintf(fp1,"%s",command);

                fclose(fp1);
                wait(SIGKILL);
                //it never prints this or execute past the wait
                printf("Here \n");

                char response[MAX_SIZE];
                if((fp2= fopen(FIFO_NAME2,"r"))==NULL)
                    perror("");

                fgets(response,fp2);
                fclose(fp2);
                //printf("%s",response);
            }

        
        else
        {
            //child
            char msg[MAX_SIZE];
                   if((fp1 = fopen(FIFO_NAME1,"r")) == NULL)

                {
                    printf("Error");
                }
                fgets(msg,fp1);
                fclose(fp1);

            
                if((fp2= fopen(FIFO_NAME2,"w+")) == NULL)
                {
                    printf("Error");
                }

                char buffer[MAX_SIZE];
                strcpy(buffer,"TEST MESSAGE");
       
                fprintf(fp2,buffer);
                fclose(fp2);

           
            fflush(stdout);
            kill(getpid(),SIGKILL);
        }

    }

}

解决方法

这里的基本问题是您不能半开FIFO。至少,除非您以非阻塞模式打开它以进行读取,否则不会这样做,而fopen()是无法做到的。通常,打开FIFO进行读取将一直阻塞,直到也打开了相同的FIFO进行写入为止,反之亦然。

在这方面,您对FIFO_NAME1感到满意。父母打开它进行写作,孩子打开它进行阅读。两者都完成后,它们都会继续。

但是随后父级调用wait()(参数也有错误,但这是一个单独的问题)。直到其子级之一终止,父级才能从该wait成功返回。只有这样,它才会尝试打开FIFO_NAME2(以供读取),但是由于子级已经终止,因此该FIFO不会被任何进程打开以进行写入,并且打开该FIFO的尝试将无限期地阻塞。

然后有一个孩子。仅由于您指定了模式"w+",它才能成功打开第二个FIFO,这样子级就可以同时满足对读取器的要求和对写入器的要求。但是,这很危险,因为如果子进程实际上并未消耗FIFO中的任何数据,那么它可能会通过尝试向其写入比内核一次愿意缓冲的数据更多的数据而死锁。而且,它不能达到您的通信目的,因为不能保证FIFO在停止为读取或写入而打开时将保留由孩子写入的数据。确实,可能没有。

您需要移动或删除wait()调用,如果选择前者,则需要检查文档以发现应该传递的参数类型。如果您愿意相信孩子不会填满管道的缓冲区,则可以将等待时间移至父对象打开FIFO_NAME2之后且尝试读取任何内容之前。就其本身而言,子进程应确保以只写模式打开第二个FIFO,以确保父子进程都在子进程开始写入之前先打开该FIFO。