C 子进程中的读取管道挂起在第二次读取上

C 子进程中的读取管道挂起在第二次读取上,c,pipe,fork,C,Pipe,Fork,我正在做一项任务,我必须创建一个由进程组成的链表,这些进程通过称为节点的管道进行通信。程序必须从根进程和名为节点1的子进程开始。用户有四个选项,我一直坚持选项1,用户应该能够添加节点和进程 根进程应该是唯一请求用户输入的进程。其余的应该循环,直到它到达读块并等待写入 当用户输入1时,程序检查当前进程是否为本例中的最后一个节点节点1。如果不是,流程将通过在每个fork之前创建的管道将输入写入下一个节点。如果是,进程将重置isLast变量并创建新管道和分叉。然后,子进程节点2循环并在读取时卡住,父进

我正在做一项任务,我必须创建一个由进程组成的链表,这些进程通过称为节点的管道进行通信。程序必须从根进程和名为节点1的子进程开始。用户有四个选项,我一直坚持选项1,用户应该能够添加节点和进程

根进程应该是唯一请求用户输入的进程。其余的应该循环,直到它到达读块并等待写入

当用户输入1时,程序检查当前进程是否为本例中的最后一个节点节点1。如果不是,流程将通过在每个fork之前创建的管道将输入写入下一个节点。如果是,进程将重置isLast变量并创建新管道和分叉。然后,子进程节点2循环并在读取时卡住,父进程紧跟其后。然后Root再次请求使用输入

问题是,程序似乎一次通过并创建节点2没有问题,但第二次通过时,节点1挂起,即使根在Add Node中写入

非常感谢您的帮助

#include <stdio.h>
#include <unistd.h>

int main(){
    int isLast = 0;
    int originPID = getpid();
    int input = 0;
    int node;
    int p[2];

    //Node 1
    printf("%s\n", "Forking");
    pipe(p);
    int pid = fork();

    //Set Node 1 to last
    if(pid == 0){
        isLast = 1;
        node = 1;
    }

    while(input != 4){
        //Node Read Block
        if(getpid() != originPID){
            printf("stuck\n");
            read(p[0], &input, sizeof(input));
            printf("free\n");
        }

        //MENU (Root Only)
        if(getpid() == originPID){      
            sleep(1);
            printf("%s", "User Options: Enter a number \n1. Add Node\n2. List Processes\n3. Remove Node\n4. Quit\n");
            scanf("%d", &input);
        }

        //(1) Add Node
        if(input == 1){
            //Checks if last. 
            if(isLast == 1){
                isLast = 0;     //Reset isLast

                //Create pipe and new process
                printf("%s\n", "Forking");
                pipe(p);
                pid = fork();
                if(pid == 0){       
                    isLast = 1;
                    node++;      //Label Node
                }
            }
            //Write to next node
            else{       
                write(p[1], &input, sizeof(input));     
            }
        }
    }
}

当最后一个节点从管道中读取1时,它必须创建一个新管道,通过该管道与即将创建的新节点通信。我想这就是为什么它叫派普。但这是一个问题,因为p[0]包含文件句柄的唯一副本,它从中读取自己的输入。当它下一次尝试读取输入时,它将尝试从它为下一个节点设置的管道中读取数据-它实际上已将自身与其前一个节点断开连接

管道在其中写入文件句柄的数组没有什么神奇之处。句柄只是整数。因此,一个简单的解决方案是让子级创建并使用从其父级继承的读取文件描述符的副本,而不是引用存储在数组元素中的值


此外,您应该确保在分叉之后,父级和子级各自关闭自己的管道末端副本,而它们不会使用该副本。父级关闭读取端;子对象关闭写入端。您可以在不使用文件描述符的情况下使程序正常工作,但至少会泄漏文件描述符。在某些情况下,打开文件描述符的额外副本可能会导致程序挂起。

输入例如a;扫描%d,&输入;那就永远不匹配了。您必须检查scanf的返回值,如果未转换任何参数,则放弃,直到行尾。此外,第61行是什么,它与问题中的代码不匹配。61在你的问题中是一个评论。另外,请阅读并将其制作成一个显示相同问题的最小程序。@AnttiHaapala对于第一个答案,您是说如果用户在提示时输入一个“a”,程序将进入一个永久循环?到目前为止,我还没有涉及到这一部分,因为我们的教授希望我们现在假设适当的输入。然而,这也会影响读取块吗?我还删除了对我遇到的问题不必要的任何代码,并删除了对第61行的引用,忘记了这里没有行。我指的是Add NodeThank you中唯一的一句话,感谢你花时间写了一个答案。很抱歉,你能详细解释一下让孩子复制文件描述符是什么意思吗?我不太明白。另外,我们的教授告诉我们不要在本作业中关闭任何管道,因为关闭的文件描述符将被回收,这显然是我们不希望的。@DazedFury,文件描述符是存储在数组元素中的值,而不是数组元素本身。您可以将相同的值存储在其他地方,即不同的变量,然后从那里使用它。至于闭包,如果你的教授告诉你不要关闭任何文件描述符,那么你当然应该按照他们说的去做。他们认为文件描述符编号可以重复使用是正确的。然而,我想不出任何好的理由来解释为什么会出现问题。