2017-05-06 8 views
0

저는 현재 C로 멀티 스레딩을 연구하고 있습니다. 그러나 우리의 명명 된 파이프를 잘 이해하지 못하는 무언가가 있습니다.
우리는 파일을 찾고 하나의 프로세스로 버퍼에 추가하는 파일 검색 시스템을 구현해야하며 두 번째 프로세스는 첫 번째 스레드에서 파일 이름을 가져 와서 해당 파일 내부에서 검색 쿼리를 찾아 첫 번째 위치로 반환해야합니다 파이프를 통해 처리. 거의 모든 작업을 수행했지만 두 프로세스간에 통신을 수행하는 방법이 혼란 스럽습니다. C fifo가 계속 차단됨

가 여기에 통신을 수행 내 코드입니다 : 내가 찾은 온라인 리소스에서
main.c를

void *controller_thread(void *arg) { 
    pthread_mutex_lock(&index_mutex); 
    int index = t_index++; /*Get an index to thread*/ 
    pthread_mutex_unlock(&index_mutex); 
    char sendPipe[10]; 
    char recvPipe[10]; 
    int fdsend, fdrecv; 
    sprintf(sendPipe, "contrl%d", (index+1)); 
    sprintf(recvPipe, "minion%d", (index+1)); 
    mkfifo(sendPipe, 0666); 
    execlp("minion", "minion", sendPipe, recvPipe, (char*) NULL); 
    if((fdsend = open(sendPipe, O_WRONLY|O_CREAT)) < 0) 
     perror("Error opening pipe"); 
    if((fdrecv = open(recvPipe, O_RDONLY)) < 0) 
     perror("Error opening pipe"); 
    while(1) { 
     char *fileName = pop(); /*Counting semaphore from buffer*/ 
     if(notFile(fileName)) 
      break; 
     write(fdsend, fileName, strlen(fileName)); 
     write(fdsend, search, strlen(search)); 
     char place[10]; 
     while(1) { 
      read(fdrecv, place, 10); 
      if(notPlace(place)) /*Only checks if all numeric*/ 
       break; 
      printf("Minion %d searching %s in %s, found at %s\n", index, 
        search, fileName, place); 
     } 
    } 
} 

,이 메인 내부 FIFO를 처리 할 수있는 방법이라고 생각합니다. 그래서 여기있다, 그냥 작동하는지 확인하기 위해 테스트 미니언를 작성하려고

minion.c

int main(int argc, char **argv) { 
    char *recvPipe = argv[1]; 
    char *sendPipe = argv[2]; 
    char fileName[100]; 
    int fdsend, fdrecv; 
    return 0; 
    fdrecv = open(recvPipe, O_RDONLY); 
    mkfifo(sendPipe, 0666); 
    fdsend = open(sendPipe, O_WRONLY|O_CREAT); 
    while(1) { 
     read(fdrecv, fileName, 100); 
     write(fdsend, "12345", 6); 
     write(fds, "xxx", 4); 
    } 
    return 0; 
} 

나는이 방법을 실행하면 스레드가 인쇄 응답이 없으면 차단받을 I 오픈 모드로 O_NONBLOCK로 변경하십시오. 그런 다음 "오류가있는 파이프를 열 수 없습니다"라는 오류가 표시되므로 어떻게 든 미니언 내부에서 recvPipe를 열 수는 없지만 실수가 무엇인지 알 수는 없습니다.

답변

1

코드에있는 문제 중 execlp()의 사용에 대한 명백한 오해가 있습니다. 성공한 경우 이 함수는을 반환하지 않으므로이 코드는 결코 실행되지 않습니다. 하나는 일반적으로 fork()을 먼저 실행 한 다음 자식 프로세스에서 execlp()을 수행합니다. execlp()이 실패하면 자식 프로세스를 종료합니다. 부모 프로세스는 결국 분기 된 자식을 기다려야 할 수도 있습니다.

또한 FIFO의 쓰기 끝을 열려고 시도 할 때 각 프로세스가 O_CREAT 플래그를 전달한다는 것은 이상하고 어쩌면 바람직하지 않습니다. 각각의 FIFO가 방금 mkfifo()으로 작성되었으므로 불필요합니다. mkfifo()이 실패하거나 열 수 있기 전에 다른 프로세스가이를 제거한 경우에도 O_CREAT을 사용하여 열려고하지 않으므로 FIFO가 아닌 일반 파일을 가져올 수 있습니다.

execlp() 문제를 해결하면 경쟁 조건도 갖게됩니다. 부모 프로세스는 자식들에게 FIFO 중 하나를 만들기 위해 의존하지만 프로세스가 그렇게 할 때까지 기다리지 않습니다. 자녀가 mkfifo()을 완료하기 전에 부모가 공개 시도에 도달하면 원하는 동작을 얻지 못합니다.

자식 프로세스를 만들기 전에 부모가 모두 FIFO를 생성하도록 제안하십시오.자식과 부모는 하나의 FIFO의 양쪽 끝을 열어서 다른 쪽 끝을 열어서 협조해야합니다. 하나는 읽기 용으로 열려 있고 다른 하나는 쓰기 용으로 동일한 FIFO를 열 때까지 차단됩니다.

또는 FIFO 대신 일반 (익명) 파이프 (pipe() 참조)를 사용할 수 있습니다. 이들은 양 끝에서 열리게 만들어지며, 상속에 의해 관련된 프로세스 간의 통신에 더 자연 스럽습니다.

어떤 경우에도 함수 호출의 반환 값을 확인하십시오. 이러한 기능은 거의 모두 실패 할 수 있습니다. 잘못 인식했을 때 발생할 수있는 엉킴을 분류하는 것보다 앞쪽을 감지하고 처리하는 것이 훨씬 낫습니다.

+0

자세한 답변을 주셔서 감사합니다. 간부의 문제가있는 부분을 이해하게되었습니다. 따라서 익명 파이프 파트의 경우 exec 인수를 통해 파이프를 전달할 수 있습니까? 모든 인수가 char *로 캐스팅 되었기 때문에 가능할 것이라고 생각하지 않았습니다. – BrokenFrog

0

Fifos는 오픈시 동기화가 필요합니다. . 기본적으로 open (s)은 블로킹 (blocking)되어 있으므로, read를위한 open은 같은 FIFO를 open 할 때까지 차단되고 반대의 경우는 통신을 위해 peer가 동기화되도록한다. 실제로 열려있는 피어가없는 동안 O_NONBLOCK을 사용하여 읽을 수 있지만 그 반대는 거짓입니다. 읽기 피어가없는 동안 쓰기 용으로 열기 때문에 오류가 발생하기 때문에 (판독기가없는 동안 프로세스에서 쓰려고하면 비 감각으로).

예를 들어 Linux Fifo manual entry을 읽을 수 있습니다.

+0

나는 당신의 대답을 정확하게 이해할 것이라고 생각하지 않는다. 그래서 나는 fondrecv = open (recvPipe, O_RDONLY | O_NONBLOCK);을 minion.c에 제안 하겠는가? – BrokenFrog