2014-11-20 3 views
2

부모와 두 자녀 사이에 정보를 보내기 위해 파이프를 사용하는 C 프로그램을 작성하려고합니다. 이 프로그램의 목적은 문자열 병합과 비슷한 것을 달성하는 것입니다. 나는 문자열의 수와 문자열을 읽었다. 문자열은 두 아이 사이에 나뉘며 각 아이가 하나의 문자열을 가질 때까지 재귀 적으로 나뉩니다. 부모님의 표준에서 읽도록 아이의 표준 입력을 리디렉션해야합니다.부모와 두 자녀 사이의 파이프

어떤 이유로 든 어떤 어린이도 첫 번째 문자열 이상을 읽지 않습니다. 이 문제는 어떻게 해결할 수 있습니까?

int main(int argc, char * argv[]) { 
    int nrrows = 0; 
    char * buffer = NULL; 
    size_t n = 0; 
    getline(&buffer, &n, stdin); 
    char * endptr; 
    nrrows = strtol(buffer, &endptr, 10); 

    char rows[nrrows][MAX_LEN]; 
    int i = 0; 
    n = 0; 
    while(i < nrrows) { 
     char * row = NULL; 
     getline(&row, &n, stdin); 
     strcpy(rows[i], row); 
     i++; 
    } 

    if(nrrows == 1) { 
     fprintf(stderr, "%s", rows[0]); 
     return 0; 
    } 

    int fdcp1[2]; 
    int fdcp2[2]; 
    if(pipe(fdcp1) < 0) { 
     fprintf(stderr, "pipe unsuccessfull\n"); 
     return EXIT_FAILURE; 
    } 
    if(pipe(fdcp2) < 0) { 
     fprintf(stderr, "pipe unsuccessfull\n"); 
     return EXIT_FAILURE; 
    } 

    pid_t chpid1 = fork(); 
    if(chpid1 < 0) { 
     fprintf(stderr, "fork unsuccessfull\n"); 
     return EXIT_FAILURE; 
    } 
    else if(chpid1 == 0) { 
     close(fdcp2[0]); 
     close(fdcp2[1]); 

     close(fdcp1[1]); 
     dup2(fdcp1[0], STDIN_FILENO); 
     execlp("./forksort", "child1", NULL); 
    }else { 
     close(fdcp1[0]); 
     dup2(fdcp1[1], STDOUT_FILENO); 

     double half = (nrrows/2); 
     int h = half; 
     char b[2]; 
     b[0] = '0' + h; 
     b[1] = '\n'; 
     write(fdcp1[1], b, sizeof(b)); 

     for(i = 0; i < h; i ++) { 
      rows[i][strlen(rows[i])] = '\0'; 
      write(fdcp1[1], rows[i], sizeof(rows[i])); 
     } 

     pid_t chpid2 = fork(); 
     if(chpid2 < 0) { 
      fprintf(stderr, "fork unsuccessfull\n"); 
      return EXIT_FAILURE; 
     }else if(chpid2 == 0) { 
      close(fdcp1[0]); 
      close(fdcp1[1]); 

      close(fdcp2[1]); 
      dup2(fdcp2[0], STDIN_FILENO); 
      execlp("./forksort", "child2", NULL); 
     }else { 
      close(fdcp2[0]); 
      dup2(fdcp2[1], STDOUT_FILENO); 
      half = (nrrows/2); 
      h = half; 
      char b[2]; 
      b[0] = '0' + (nrrows - h); 
      b[1] = '\n'; 
      write(fdcp2[1], b, sizeof(b)); 

      for(i = h; i < nrrows; i ++) { 
       rows[i][strlen(rows[i])] = '\0'; 
       write(fdcp2[1], rows[i], sizeof(rows[i])); 
      } 
     } 
    } 
    return 0; 
} 
+0

'pid_t chpid2 = fork(); pid_t chpid1 = fork();'첫 번째 자식의 추가 자식 만들기가 발생합니까? chpid2와 chpid1은 parent에 의해 생성되지만 다른 chpid1은 parent의 chpid2에 의해 생성됩니다. –

+0

그래, 알아. 그러나 그들은 여전히 ​​읽을 수 없습니다. – Syn

+0

죄송합니다. 시간이 없으며 코드로 다이빙 할 예정입니다.하지만 다른 아이가 파이프를 막 닫았을 수도 있습니다. 분기 코드를 수정하고 동작을 수정하는지 확인하십시오. –

답변

0

열린 스트림과 관련된 파일 설명자를 수정하는 것은 나쁜 소식입니다. 나는 그것이 당신에게 문제를 야기 할 가능성이 높다고 설명 할 것이고, 또한 여기서 그것을 할 필요가 없다. 대신 부모는 fdopen()을 사용하여 파이프의 끝 부분에 새 스트림을 열고 표준 스트림 대신 해당 스트림을 통해 하위 스트림과 I/O를 수행해야합니다. 더 안전해질뿐만 아니라 프로세스의 원래 표준 스트림을 부모 프로세스와 통신 할 수있게합니다.

이러한 접근 방식을 사용하면 각 프로세스의 메모리에서 블록을 중복 버퍼링하는 대신 프로세스간에 앞뒤로 정렬되도록 문자열을 스트리밍 할 수도 있습니다. 예를 들어, 다음과 같이 할 수 있습니다 :

#define _GNU_SOURCE 
#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#include <unistd.h> 

int main(int argc, char * argv[]) { 
    char * buffer = NULL; 
    size_t buflen = 0; 
    int nrrows; 
    int fdpc1[2]; 
    int fdcp1[2]; 
    int fdpc2[2]; 
    int fdcp2[2]; 
    pid_t chpid1; 
    pid_t chpid2; 
    FILE *pipeout; 
    FILE *pipein1; 
    FILE *pipein2; 
    int half; 
    int i; 

    fprintf(stderr, "%s!!!!!!!!!!!!!!!!!\n", argv[0]); 

    getline(&buffer, &buflen, stdin); 
    fprintf(stderr, "number: %s from %s\n", buffer, argv[0]); 
    nrrows = strtol(buffer, NULL, 10); 

    if(nrrows <= 0) { 
     fprintf(stderr, "This is not a valid >0 number\n"); 
     return EXIT_FAILURE; 
    } else if (nrrows == 1) { 
     /* ... read and echo back the one row ... */ 
     getline(&buffer, &buflen, stdin); 
     fprintf(stderr, "%s", buffer); 
     return EXIT_SUCCESS; 
    } 

    /* There are at least two rows to sort */ 

    if (pipe(fdcp1) < 0) { 
     fprintf(stderr, "pipe unsuccessfull\n"); 
     return EXIT_FAILURE; 
    } 
    if (pipe(fdpc1) < 0) { 
     fprintf(stderr, "pipe unsuccessfull\n"); 
     return EXIT_FAILURE; 
    } 

    chpid1 = fork(); 
    if (chpid1 == 0) { 
     /* this is child process 1 */ 
     close(fdcp1[1]); 
     close(fdpc1[0]); 
     dup2(fdcp1[0], STDIN_FILENO); 
     close(fdcp1[0]); 
     dup2(fdpc1[1], STDOUT_FILENO); 
     close(fdpc1[1]); 
     execlp("./forksort", "child1", NULL); 
    } else if (chpid1 < 0) { 
     fprintf(stderr, "fork unsuccessfull\n"); 
     return EXIT_FAILURE; 
    } 

    /* this is the parent process */ 

    close(fdcp1[0]); 
    close(fdpc1[1]); 

    if (pipe(fdcp2) < 0) { 
     fprintf(stderr, "pipe unsuccessfull\n"); 
     return EXIT_FAILURE; 
    } 
    if (pipe(fdpc2) < 0) { 
     fprintf(stderr, "pipe unsuccessfull\n"); 
     return EXIT_FAILURE; 
    } 

    chpid2 = fork(); 
    if (chpid2 == 0) { 
     /* this is child process 2 */ 
     close(fdcp1[1]); 
     close(fdpc1[0]); 
     close(fdcp2[1]); 
     close(fdpc2[0]); 
     dup2(fdcp2[0], STDIN_FILENO); 
     close(fdcp2[0]); 
     dup2(fdpc2[1], STDOUT_FILENO); 
     close(fdpc2[1]); 
     execlp("./forksort", "child2", NULL); 
    } else if (chpid2 < 0) { 
     fprintf(stderr, "fork unsuccessfull\n"); 
     return EXIT_FAILURE; 
    } 

    /* this is the parent process */ 

    close(fdcp2[0]); 
    close(fdpc2[1]); 

    /* copy the first half of the lines from input to child 1 */ 

    pipeout = fdopen(fdcp1[1], "w"); 
    if (pipeout == NULL) { 
     fprintf(stderr, "fdopen unsuccessful\n"); 
     return EXIT_FAILURE; 
    } 

    half = nrrows/2; 
    fprintf(pipeout, "%d\n", half); 
    for (i = 0; i < half; i += 1) { 
     getline(&buffer, &buflen, stdin); 
     fprintf(stderr,"row[%d] from %s: %s", i, argv[0], buffer); 
     fputs(buffer, pipeout); 
    } 
    fclose(pipeout); 

    /* copy the second half of the lines from input to child 2 */ 

    pipeout = fdopen(fdcp2[1], "w"); 
    if (pipeout == NULL) { 
     fprintf(stderr, "fdopen unsuccessful\n"); 
     return EXIT_FAILURE; 
    } 

    fprintf(pipeout, "%d\n", nrrows - half); 
    for (; i < nrrows; i += 1) { 
     getline(&buffer, &buflen, stdin); 
     fprintf(stderr,"row[%d] from %s: %s", i, argv[0], buffer); 
     fputs(buffer, pipeout); 
    } 
    fclose(pipeout); 

    /* now read and merge sorted lines from the children */ 

    pipein1 = fdopen(fdpc1[0], "r"); 
    pipein2 = fdopen(fdpc2[0], "r"); 
    if (pipein1 == NULL || pipein2 == NULL) { 
     fprintf(stderr, "fdopen unsuccessful\n"); 
     return EXIT_FAILURE; 
    } 

    /* ... */ 

    fclose(pipein1); 
    fclose(pipein2); 

    return 0; 
} 
+0

그리고 제한된 테스트에서, 모든 자식 프로세스가 성공적으로 의사 소통을하는 것으로 보입니다. –

+0

내 코드를 업데이트하고 요구 사항을 자세히 설명했습니다. – Syn

+0

불명확 한 경우 : 각 부모는 자녀들과 이야기하기 위해 파이프의 끝 부분에 새로운 스트림을 엽니 다. 다른 한편으로, 그 파이프의 아이들의 끝은 그들의 표준 스트림에 맵핑된다. –

관련 문제