2012-05-24 2 views
0

과제가 빡빡하지만 막혔습니다. 오류가 발생하고 내가 잘못하고있는 것을 이해하지 못합니다.C 파이프 초기화 오류

그래서 주에서 나는 세 명의 아이들을 만듭니다. 첫 번째와 두 번째 사이에는 파이프 (pipe12)가 있습니다. 두 번째와 세 번째 사이에는 파이프 (pipe23)가 있습니다. 이제 첫 번째 자식 (reader)이 읽을 준비가되면 pipe12을 닫지 만 두 번째 자식의 읽기는 EOF이 아닙니다. 둘째로 두 번째 자식이 pipe23에 쓰려고 할 때 자식이 충돌합니다.

내가 파이프의 초기화에 뭔가 잘못된 것 같지만, 뭐라구?

void reader(void) 
{ 
    atexit(*reader_exit); 
    if((readfile = fopen(calculatorfile,"r"))==NULL) 
    { 
     printf("R send error to errorHandler");  //errpipe! 
     exit(0); 
    } 
    char line[50]; 
    const char *valid_characters = "-/*\n"; 
    while(fgets (line, sizeof line, readfile) != NULL) 
    { 
     printf("R reading ...%s",line); 
     char *c = line; 
     while(*c) 
     { 
      if(!strchr(valid_characters,*c)) 
      { 
       printf("R invalid character: %c in %s",*c,line); 
       line[0]=0; 
       break; 
      } 
      c++; 
     } 
     write(pipe12[1],line,sizeof line); 
    } 
    exit(0); 
} 

void reader_exit(void) 
{ 
    printf("R reader exit\n"); 
    fclose(readfile); 
    close(pipe12[1]); 
    close(tasks[childnr].errorpipe[1]); 
} 

그리고 둘째 아이 :

부모

for(childnr=2; childnr>=0;childnr--) 
{ 
    tasks[childnr].pid=fork(); 
    if(tasks[childnr].pid==-1) 
    { 
     printf("fork error\n"); 
     exit(1); 
    } 
    else if(tasks[childnr].pid==0) 
    { 
     switch(childnr) 
     { 
      case 0: 
       close(pipe12[0]); 
       close(pipe23[0]); 
       close(pipe23[1]); 
       reader(); 
       break; 
      case 1: 
       close(pipe12[1]); 
       close(pipe23[0]); 
       tokenizer(); 
       break; 
      case 2: 
       close(pipe12[0]); 
       close(pipe12[1]); 
       close(pipe23[1]); 
       evaluator(); 
       break; 
      default: 
       printf("childnr error\n");      //errorhandling 
     }   
    } 
    else 
     close(tasks[childnr].errorpipe[1]); 
} 
close(pipe12[0]); 
close(pipe12[1]); 
close(pipe23[0]); 
close(pipe23[1]); 
... continue with the parent 

이 첫 번째 자식이다

void tokenizer(void) 
{ 
    atexit(*tokenizer_exit); 
    char buffer[50]; 
    while(read(pipe12[0],buffer,sizeof buffer)!=EOF) 
    { 
     printf("T %s",buffer); 
     char *token = strtok(buffer," "); 
     while(token!=NULL) 
     { 
      printf("T %s\n",token); 
      write(pipe23[1],token,sizeof token); 
      token = strtok(NULL, " "); 
     } 
     sleep(2); 
    } 
    exit(0); 
} 
+0

파일 설명자를'reader (pipe12 [1])'로 전달하여 독자의 일반성을 향상시킬 수 있습니다. tokenizer : tokenizer (pipe12 [0], pipe23 [1]);와 평가자 : evaluationator (pipe23 [0]);와 비슷하게. 독자에게는 파일 이름도 전달해야합니다 :'reader (calculatorfile, pipe12 [1]);'. –

+0

고마워, 내가 할께. – Kat

+0

하위 프로세스는 어떻게 충돌합니까? 'SIGPIPE' 또는'SIGSEGV' /'SIGBUS'? – C2H5OH

답변

1

기본 문제가 있음을 EOF에 read() 0을 반환 , -1 또는 EOF가 아닙니다.

귀하의 코드가 같은 루프가 있어야합니다

while (read(pipe12[0], buffer, sizeof buffer) > 0) 
내가 atexit()에 등록 된 기능을 피하는 것이 좋습니다

; 그들은 당신에게 전역 변수를 사용하도록 강요합니다. 귀하의 1 차 하위 기능이 자신의 정리를 수행하도록하십시오.

reader(pipe12[1]) 
tokenizer(pipe12[0], pipe23[1]); 
evaluator(pipe23[0]); 
: 토크 나이와 평가자와 유사하게 당신은 여기에 파일 기술자를 전달하여 독자의 일반성을 향상시킬 수

, 그리고이보다 쉽게 ​​코멘트에서 만든 제안을 구현하는 것 독자

, 당신은 아마 너무 파일 이름을 전달해야합니다

reader(calculatorfile, pipe12[1]); 

,536,913 63,210

단지 작품에 대한이 코드 :

#include <stdio.h> 
#include <unistd.h> 
#include <sys/wait.h> 
#include <stdlib.h>  /* atexit() */ 
#include <string.h> 

static int pipe12[2]; 
static int pipe23[2]; 

struct task 
{ 
    pid_t pid; 
}; 
static struct task tasks[5]; 

static void evaluator(int i_fd); 
static void tokenizer(int i_fd, int o_fd); 
static void reader(char const *file, int o_fd); 

int main(void) 
{ 
    pipe(pipe12); 
    pipe(pipe23); 
    for (int childnr=2; childnr>=0;childnr--) 
    { 
     tasks[childnr].pid=fork(); 
     if (tasks[childnr].pid==-1) 
     { 
      printf("fork error\n"); 
      exit(1); 
     } 
     else if (tasks[childnr].pid==0) 
     { 
      switch (childnr) 
      { 
       case 0: 
        close(pipe12[0]); 
        close(pipe23[0]); 
        close(pipe23[1]); 
        reader("data-file", pipe12[1]); 
        break; 
       case 1: 
        close(pipe12[1]); 
        close(pipe23[0]); 
        tokenizer(pipe12[0], pipe23[1]); 
        break; 
       case 2: 
        close(pipe12[0]); 
        close(pipe12[1]); 
        close(pipe23[1]); 
        evaluator(pipe23[0]); 
        break; 
       default: 
        printf("childnr error\n");      //errorhandling 
        break; 
      }   
     } 
    } 
    close(pipe12[0]); 
    close(pipe12[1]); 
    close(pipe23[0]); 
    close(pipe23[1]); 

    printf("Parent waiting...\n"); 
    while (wait(0) != -1) 
     ; 
    printf("Brats are all dead!\n"); 
    return(0); 
} 

static void reader(char const *file, int o_fd) 
{ 
    FILE *fp; 
    if ((fp = fopen(file, "r"))==NULL) 
    { 
     printf("R send error to errorHandler");  //errpipe! 
     exit(0); 
    } 
    char line[50]; 
    const char *valid_characters = "-/*\n"; 
    while (fgets(line, sizeof(line), fp) != NULL) 
    { 
     printf("RI %s", line); 
     char *c = line; 
     while (*c) 
     { 
      if (!strchr(valid_characters, *c)) 
      { 
       printf("R invalid character: %c in %s\n", *c, line); 
       line[0] = '\0'; 
       break; 
      } 
      c++; 
     } 
     if (line[0] != '\0') 
     { 
      printf("RO %s", line); 
      write(o_fd, line, strlen(line)); 
     } 
    } 
    close(o_fd); 
    fclose(fp); 
    printf("Reader exiting\n"); 
    exit(0); 
} 

static void tokenizer(int i_fd, int o_fd) 
{ 
    char buffer[50]; 
    int nbytes; 
    while ((nbytes = read(i_fd, buffer, sizeof(buffer))) > 0) 
    { 
     buffer[nbytes] = '\0'; 
     printf("TI %*s\n", nbytes, buffer); 
     char *token = strtok(buffer, " \n"); 
     while (token!=NULL) 
     { 
      printf("TO %s\n", token); 
      write(o_fd, token, strlen(token)); 
      token = strtok(NULL, " "); 
     } 
     sleep(2); 
    } 
    printf("Tokenizer exiting\n"); 
    exit(0); 
} 

static void evaluator(int i_fd) 
{ 
    char buffer[50]; 
    int nbytes; 
    while ((nbytes = read(i_fd, buffer, sizeof(buffer))) > 0) 
    { 
     printf("EI %*s\n", nbytes, buffer); 
     buffer[nbytes] = '\0'; 
     char *token = strtok(buffer, " "); 
     while (token!=NULL) 
     { 
      printf("EO %s\n", token); 
      token = strtok(NULL, " "); 
     } 
     sleep(2); 
    } 
    close(i_fd); 
    printf("Evaluator exiting\n"); 
    exit(0); 
} 

포함하는 데이터 파일을 감안할 때 : 생산 프로그램의

123 456 
123 + 234 * 547/987 - 1 

하나 실행 :

Parent waiting... 
RI 123 456 
RO 123 456 
RI 123 + 234 * 547/987 - 1 
RO 123 + 234 * 547/987 - 1 
Reader exiting 
TI 123 456 

TO 123 
TO 456 

EI 123 
EO 123 
TI 123 + 234 * 547/987 - 1 
EI 456 

TO 123 
TO + 
TO 234 
TO * 

TO 547 
TO/
EO 456 

TO 987 
TO - 
TO 1 

EI 123+234*547/987-1 

EO 123+234*547/987-1 

Tokenizer exiting 
Evaluator exiting 
Brats are all dead! 

참고 자료 read()로 읽어을에있다 명시 적으로 널 종료해야한다. fgets()으로 읽은 데이터는 그렇지 않습니다. 또한 기본적인 디버깅이 어떻게 이루어 졌는지 주목하십시오. 모든 입력이 에코되면 다음 프로그램의 모든 출력도 에코됩니다. 이로 인해 문제가있는 곳을 쉽게 (또는 적어도 더 쉽게) 알 수 있습니다. 극단적 인 경우 stderr 또는 printf() 이후에 fflush()에 글을 쓰는 것이 좋습니다. 숫자가 하나 인 인수를 사용하여 printf()을 사용하는 것과 같이 차선책 인 세부 정보가 많이 있습니다.작업 구조는이 코드에서 중복됩니다. 파이프 배열은 수정 된 코드의 지역 변수가 될 수 있습니다.

+0

이렇게하면 끝나지 않은 읽기 문제가 해결되었습니다. 그러나 프로그램은 여전히 ​​토크 나이저의 첫 번째 글에서 충돌합니다. – Kat

+0

예제 실행은 tokenizer가 충돌하지 않고 평가자에게 성공적으로 쓰는 것을 보여줍니다. 코드와 코드가 다른 점은 무엇입니까? –

+0

좋아, 지금 일한다. 문제는 내가 아직 평가자를위한 코드를 작성하지 않았기 때문에 토크 나이저가 파이프에 무엇을 넣었는지 아직 읽지 못했다는 것입니다. 감사 – Kat