0

嗨,我必须开发这个程序来创建 4 个孩子,然后依次让他们做一个简单的操作。第一个是求和,第二个是余数,第三个是乘法,第四个是除法。父亲将他希望孩子“计算”的两个数字的字符串写在套接字上,每个孩子都应该阅读这个字符串,提取数字并进行运算。显然,作为两个管道,每次字符串都需要父亲写入,因为在孩子中读取。我真的不明白为什么在第二次迭代中,我收到了父亲写的 SIGPIPE。有人可以解释我为什么吗?我在调试中损失了 3 天,但我没有找到任何东西。非常感谢。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h> 

/*
fd_0 padre escribe y hijo lee ==== padre cierra fd_0[0] y hijo cierra fd_0[1]
fd_1 hijo escribe y padre lee ===  padre cierra fd_1[1] y hijo cierra fd_1[0]
*/


int main (int argc, char * argv[]){


    char * str = malloc(100*sizeof(char));//hijo
    char readbuffer_h[150];

    char * stringa = malloc(100*sizeof(char));//padre
    char readbuffer_p[150];


    int a,b;
    int x,y;
    int n = 4;
    int i,status,nbytes, pipe_status;
    int pid, ppid,yo,padre;
    int fd_0[2], fd_1[2] ;



    pipe_status=pipe(fd_0);
    if(pipe_status==- 1) {
        perror("Error creando la tuberia 0\n");
        exit(EXIT_FAILURE);
    }


    pipe_status=pipe(fd_1);
    if(pipe_status== -1) {
        perror("Error creando la tuberia 1 \n");
        exit(EXIT_FAILURE);
    }   



    for(i=0; i< n; i++){

        if ((pid=fork()) <0 ){
        printf("Error al emplear fork\n");
        exit(EXIT_FAILURE);
        }

/*-------------------------------------------------------------------------------------------------------------------------------------------------*/

        else if (pid ==0){// soy el hijo


            yo = getpid();
            padre = getppid();
            printf("HIJO: %d, mi padre es: %d\n", yo, padre);    

            close(fd_0[1]);
            close(fd_1[0]);

            //TODO


            nbytes = read(fd_0[0], readbuffer_h, sizeof(readbuffer_h));

            sscanf(readbuffer_h, "%d,%d", &x, &y);


            switch(i) {

                case 0 :
                    //TODO
                    sprintf(str, "Datos enviados a través de la tuberia por el proceso hijo: %d. Primero operando: %d, segundo operando: %d. La suma es %d", yo,x,y,(x+y));
                    break;

                case 1 :
                    //TODO
                    sprintf(str, "Datos enviados a través de la tuberia por el proceso hijo: %d. Primero operando: %d, segundo operando: %d. La resta es %d", yo,x,y,(x-y));
                    break;          

                case 2 :
                    //TODO
                    sprintf(str, "Datos enviados a través de la tuberia por el proceso hijo: %d. Primero operando: %d, segundo operando: %d. El producto es %d", yo,x,y,(x*y));
                    break;

                case 3 :
                    //TODO
                    sprintf(str, "Datos enviados a través de la tuberia por el proceso hijo: %d. Primero operando: %d, segundo operando: %d. El cociente es %d", yo,x,y,(x/y));
                    break;

            }


            write(fd_1[1], str, strlen(str));


            exit(EXIT_SUCCESS); 
        }

/*-------------------------------------------------------------------------------------------------------------------------------------------------*/


        else{ //soy el padre
            yo = getpid();
            printf("PADRE:%d\n", yo);

            a = 3; b = 4;

            close(fd_0[0]);
            close(fd_1[1]);


            sprintf(stringa,"%d,%d",a,b);
            printf("Stringa padre : %s\n", stringa);
                fflush(stdout);

            write(fd_0[1],stringa,strlen(stringa)); // questa write non va a buon fine


            wait(&status);

            read(fd_1[0], readbuffer_p, sizeof(readbuffer_p));
            printf("%s\n",readbuffer_p);
                fflush(stdout);

        }


    }

close(fd_0[0]);
close(fd_0[1]);
close(fd_1[0]);
close(fd_1[1]);


return 0;
}
4

1 回答 1

1

尝试使用相同的管道与每个孩子交流,您会遇到麻烦。

您在程序开始时创建了两个管道。在循环的第一次迭代中,父节点分叉,子节点继承父节点的所有打开文件描述符。子关闭它不需要的管道末端,而父关闭不需要的管道末端。沟通按预期进行(我想)——到目前为止一切都很好。

但现在考虑循环的第二次迭代。您再次分叉,子级再次继承父级的打开文件描述符。但是现在,孩子想要使用的文件描述符在循环的前一次迭代中被父母关闭了。当孩子尝试使用这些文件描述符时,它得到一个EPIPE而不是一个,我有点惊讶,但我一点也不惊讶它的读取尝试失败。EBADF

最干净的做法是为每个孩子创建一对新的管道,而不是尝试重用一组管道。如果你想让它只与一对一起工作,那么父进程必须避免关闭任何管道末端(尽管如果你愿意,子进程可能会关闭它们的副本)。

于 2017-02-24T22:07:37.000 回答