2017-05-17 11 views
0

다음은 두 자식 프로세스간에 올바른 파이핑을 수행하는 방법을 이해하려고 시도한 것입니다. 나는 한 리눅스 명령의 출력을 다른 명령에 넘겨주고 프로그램을 성공적으로 반환하려고한다. 그러나 나는 두 번째 자식이 갇혀 있고 부모는이 자식을 영원히 기다리고 있다고 생각합니다. 나는 왜이 코드가 오랫동안 빠져 나가고 있는지 알아 내려고 노력 해왔다. 나는 C 시스템 프로그래밍에 관해서는 다소 멍청하다. 그러나 나는 배우려고 노력하고있다.이 C 코드의 문제점은 무엇입니까? 아이가 돌아 오지 않을까요?

아무도 프로그램이 종료되지 않는 이유를 알고 있지만 고양이에 매달려 있습니까?

도움을 주시면 감사하겠습니다.

감사합니다.

#include <stdio.h> 
#include <stdlib.h> 
#include <signal.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include <sys/wait.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
int main() 
{ 
    char *a[2] = {"/bin/ls", NULL}; 
    char *b[2] = {"/bin/cat", NULL}; 
    char *envp[2] = {getenv("PATH"), NULL}; 
    int fd[2], status; 
    pipe(fd); 
    int old_std_out = dup(1); 
    int old_std_in = dup(0); 
    dup2(fd[1], 1); 
    int pid = fork(); 
    switch(pid) 
    { 
     case -1: 
      perror("Forkscrew"); 
      exit(1); 
      break; 
     case 0: 
      execve(a[0], a, envp); 
      exit(0); 
      break; 
     default: 
      waitpid(-1, &status, 0); 
      dup2(old_std_out, 1); 
      break; 
    } 
    dup2(fd[0], 0); 
    pid = fork(); 
    switch(pid) 
    { 
     case -1: 
      perror("Forkscrew"); 
      exit(1); 
      break; 
     case 0: 
      execve(b[0], b, envp); 
      exit(0); 
      break; 
     default: 
      waitpid(-1, &status, 0); 
      dup2(old_std_in, 0); 
      break; 
    } 
    printf("\n"); 
    return 0; 
} 
+0

두 마리의 고양이를 집행하지 않습니까? 다시 포크를 탄 다음 두 포크를 다시 줍니까? –

+0

'ls' 결과가 파이프 버퍼에 맞지 않으면 어떻게 될 것이라고 생각하십니까? – EOF

+0

@SamKuhmonen 두 마리의 고양이를 돌보는 중입니까? 아마도? 첫 번째는 배열 a에서 exec를하고 배열 b에서 다음 exec를 수행합니다. fork()가 자식과 부모를 반환한다고 생각했습니다. – user3499524

답변

2

프로그램에 두 가지 교착 상태가 있습니다.

먼저 파이프에 기록 할 때, 제 자식 (ls)는 (cat)를하는 경우 waitpid()ls이 종료 될 때까지 리턴되지 않으며 ls 번째 자식까지 종료되지 차단할 수는 수, 실행을 시작 waitpid()이 반환 될 때까지는 발생하지 않습니다. => 교착 상태.

둘째, cat은 쓰기 끝의 모든 파일 설명자가 닫힐 때까지 stdin에서 읽습니다. 부모 프로세스 cat 모두 쓰기 끝 사본이 있습니다. cat에는 이 명시 적으로 없으며에 대해 알지 못합니다. 쓰기 작업의 유일한 복사본이 동일한 프로세스 (이 교착 상태를 피하기 위해)에있는 경우 일부 운영 체제에서는 read()이 차단되지 않지만 이는 보장되지 않습니다. 어느 쪽이든, 부모 프로세스는 filedescriptor의 복사본을 유지하고 파이프의 쓰기 끝이 닫힐 때까지 대기하는 자식 프로세스의 자식 프로세스 waitpid()을 교착 상태로 유지하기 때문에 교착 상태가 다시 발생합니다.

종종 프로그램을 단순화하는 것은 이러한 문제를 해결 :

보시다시피
#include <stdio.h> 
#include <stdlib.h> 
#include <signal.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include <sys/wait.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
int main() 
{ 
    char *a[2] = {"/bin/ls", NULL}; 
    char *b[2] = {"/bin/cat", NULL}; 
    char *envp[2] = {getenv("PATH"), NULL}; 
    int fd[2], status; 
    pipe(fd); 
    //int old_std_out = dup(1); /*No need to copy stdout...*/ 
    //int old_std_in = dup(0); /*...or stdin...*/ 
    //dup2(fd[1], 1);   /*...if you wait dup2()ing until you need to*/ 
    int pid = fork(); 
    switch(pid) 
    { 
     case -1: 
      perror("Forkscrew"); 
      exit(1); 
      //break; /*unreachable*/ 
     case 0: 
      dup2(fd[1], STDOUT_FILENO); /*NOW we dup2()*/ 
      close(fd[0]); /*no need to pass these file descriptors to...*/ 
      close(fd[1]); /*...a program that doesn't expect to have them open*/ 
      execve(a[0], a, envp); 
      exit(0); /*might want an error message*/ 
      //break; /*unreachable*/ 
     default: 
      //waitpid(-1, &status, 0); /*don't wait yet*/ 
      //dup2(old_std_out, 1); 
      close(fd[1]); /*we don't need this in the parent anymore*/ 
      break; 
    } 
    //dup2(fd[0], 0); /*not needed anymore*/ 
    pid = fork(); 
    switch(pid) 
    { 
     case -1: 
      perror("Forkscrew"); 
      /*might want to ensure the first child can terminate*/ 
      exit(1); 
      //break; /*unreachable*/ 
     case 0: 
      dup2(fd[0], STDIN_FILENO); 
      close(fd[0]); /*again, cat doesn't expect a fourth fd open*/ 
      execve(b[0], b, envp); 
      /*again, error message would be nice*/ 
      exit(0); 
      //break; 
     default: 
      //waitpid(-1, &status, 0); 
      //dup2(old_std_in, 0); 
      break; 
    } 
    waitpid(-1, &status, 0); /*don't wait until both children are created*/ 
    waitpid(-1, &status, 0); 
    printf("\n"); 
    return 0; 
} 

, 나는 개선을위한 제안의 숫자를 왼쪽했지만,이 이미 지금은 잘 작동합니다의 execve()의 작품은 확실히 제공했다.

+0

도움을 다시 주셔서 감사합니다. 몇 시간의 좌절감을 덜어 줬습니다. – user3499524