이중fork와 pipe 사용시 hang걸리는 현상
글쓴이: smartksh / 작성시간: 목, 2006/02/16 - 3:33오후
안녕하세요.
아래의 코드는 c++코드입니다.
이중 fork를 이용하여 손자 프로세스를 생성하고,
pipe를 이용하여 손자 프로세스의 pid를 부모 프로세스로 전달하는 함수입니다.
이 함수가 1분 마다 호출되는 프로그램을 구현하여 Linux ES3에서 장시간 확인한 결과,
평소에는 문제가 없는데, 어느 순간부터는 부모 프로세스는 read() 상태에서 멈춰있고,
자식프로세스는 write() 상태에서 멈춰있는 현상이 발생하고 있습니다.
자식 프로세스를 kill 시키면 부모 프로세스는 멈췄던 동작을 이어서 수행합니다.
제가 보기에는 자식 프로세스가 write() 상태에서 blocking되어 버린것 같습니다.
코드상 잘못된 부분이 있는지, 개선방안이나 회피 방법은 없는지 알고 싶습니다.
여러분의 관심과 답변 부탁드립니다.
int fork2() { pid_t pid; int status; int fd[2]; if ( pipe(fd) == -1 ) return -1; pid=fork(); if ( pid == 0 ) { pid_t pid2 = fork(); if ( pid2 == 0 ) { close(fd[0]); close(fd[1]); // 손자 프로세스의 실행 execve(..........); exit(0); } else { close(fd[0]); char writebuffer[16]; sprintf(writebuffer, "child pid = %d%c", pid2, 0); // 손자의 pid를 전달한다. write(fd[1], writebuffer, strlen(writebuffer)); close(fd[1]); exit(0); } } else if ( pid > 0 ) { close(fd[1]); char readbuffer[16]; memset(readbuffer, 0, 16); // 손자의 pid를 읽는다. int nbytes = read(fd[0], readbuffer, sizeof(readbuffer)); close(fd[0]); printf("%s\n", readbuffer); } if ( pid < 0 || waitpid(pid, &status, 0) < 0 ) return -1; ............. }
Forums:
이상한 부분 정리.
1. pipe를 생성하는 위치가 잘못됨.
pipe는 부모와 자식 프로세스간의 통신밖에 지원하지 않습니다.
때문에, 할아버지와 손자사이에서 파이프를 직접적으로 공유할 수 있는 방법은 없습니다.
2. waitpid 를 한군데 더 넣어주어야 함.
할아버지의 자식 프로세스가 종료되는 시점을 체크하는 부분이 추가되어야 함.
이러한 상황이라면.. Named Pipe가 적절한 대안이 될 수 있으며, 좀 더 자세한 내용은 다음 사이트를 통해서 확인이 가능합니다.
http://wiki.kldp.org/wiki.php/%B8%AE%B4%AA%BD%BA%C7%C1%B7%CE%B1%D7%B7%A1%B8%D3%B8%A6%C0%A7%C7%D1%B0%A1%C0%CC%B5%E5#s-6.3
아울러 다음은, 참고가 될 만한 소스입니다. 작업 환경이 제공되지 않아.. 컴파일은 안해보았습니다. 에러가 약간 있을 듯 하지만..
의미 전달하는 무리가 없으니.. ^^;;; 알아서 보세요.. ^^;;;
- 인생은 스스로 -
Re: 이상한 부분 정리.
먼저 aswip님 의견에 대한 반론입니다 :twisted:
정말 그런 제한이 있나요? 아시다시피 pipe로 만든 파일 디스크립터는 FD_CLOEXEC 플래그를 설정해 주지 않는 한 fork() 과정에서 자식 프로세스에게 복사되고 그 pipe는 공유됩니다. 그렇다면 (자식이 손자를 낳기 전에 연락을 끊지만 않는다면) 손자 프로세스 역시도 복사된 파일 디스크립터를 물려받게 됩니다. 그 파일 디스크립터를 이용하면 2대 사이에 걸친 통신에 별 문제가 없지 않을까요?
더불어 smartksh님의 소스는 조부보-손자간이 아니라 부모-자식간에서 pipe 통신을 하고 있습니다. :twisted:
smartksh님의 소스에서 할아버지는 자기 자식의 뒷수습을 잘 하고 있습니다. 자식(제2대)이 손자(제3대) 프로세스에 대해서 waitpid()를 하지 않는 걸 말씀하시는 게 아닐까 싶기도 합니다만...
정석대로 하자면 자식들에 대해서 waitpid()를 해주어야 합니다만, smartksh님 소스의 경우 자식 프로세스가 자식을 낳고서 얼른 종료되기에 손자 프로세스는 init에게 입양되고, 사망 후의 뒷수습도 init 프로세스가 알아서 해 주는 것이 예상 실행 방식이라고 추측됩니다.
다만 자식 프로세스가 종료하기 전에 손자 프로세스가 execve()에 실패하거나 execve()로 실행된 프로세스가 일찍 종료하는 경우는 손자가 한동안 좀비놀이를 하게 됩니다. 이게 문제의 원인이라면 block되어 있는 상태에서 ps를 했을 때 좀비 프로세스가 보일 테니... startksh님이 확인을 해주시겠군요-
----
startksh님의 소스로 돌아가자면,
재현이 쉽지 않네요. 올려주신 소스에서 찝찝한 부분이라면 자식 프로세스가 sprintf() 하면서 buffer overflow가 날 수 있다는 정도입니다.
"strace -f" 정도로 block되는 부분을 정확히 확인하고 block 되는 부분에서 시스템콜로 매개변수들이 정확히 넘어가고 있는지 확인해 보시는 건 어떨까 합니다. block된 순간 출력 결과의 뒷쪽 부분을 올려 주셔도 좋겠습니다.
$PWD `date`
자식 프로세스를 종료하는 코드가 없군요.오래 두면 이상하다구요?
자식 프로세스를 종료하는 코드가 없군요.
오래 두면 이상하다구요?
혹시 해당 프로세스가 몇개 떠있는지 보셨나요?
저거 계속해서 프로세스 개수가 증가합니다.
프로그램 실행 후에 몇분 있다가 ps aux 를 한번 해보세요.
아래 소스 컴파일 해서 실행해 보세요.
원하시는데 상상하신대로 작동하는지 화면에 출력되는 문구 확인해 보시구요.
아마 예상하지 못한 방식으로 작동하고 있을 겁니다.
아마 이렇게 작동하는 코드를 원하셨을 겁니다.[code:1]#incl
아마 이렇게 작동하는 코드를 원하셨을 겁니다.
제의 질문에 대한 관심에 감사드립니다.이중fork을 사용하는 이유
제의 질문에 대한 관심에 감사드립니다.
이중fork을 사용하는 이유는,
부모보다 자식이 먼저 종료될 때 발생하는 defunct현상을 없애기 위한 것입니다.
wariua님의 말씀대로, 현재의 코드상에서도
부모(2대)보다 자식(3대)이 먼저 종료될 경우에는 자식(3대) 프로세스가 defunct되는 현상이 발생합니다.
이런 현상은 정상적인 경우 임시적인 것이므로 큰 문제가 되지 않는다고 생각합니다.
이중fork을 1분마다 반복하면서 몇 일간 지켜보면서
ps 명령으로 확인해보면 프로세스가 늘어나지는 않습니다.
strace 명령으로도 확인해 보았는데, 부모(1대)는 pause인가 sleep 상태였고,
자식(2대)는 MUTEX_WAIT(?) 인가 하는 상태였던걸로 기억합니다.
hang이 걸리는 현상이 서버의 사양이나 상태(리소스가 별로 없는 상태 등..)와 관계가 있을지 궁금합니다.
처음 올려주신 소스를 구동하면 프로세스가 계속 증가하지 않는 다고요?
처음 올려주신 소스를 구동하면 프로세스가 계속 증가하지 않는 다고요?
음..
처음 소스대로라면 계속 증가해야 맞는건데요.
자식의 프로세스가 종료하지 않고 계속 살아 있기 때문에
부모는 waitpid 에서 영원히 대기 중이며, 자식은 1분 슬립하고 다시 구동하여 포크해서 또 부모는 waitpid 로 영원히 대기 하고 자식은 다시 1분 슬립하는게 반복되는 코드인데요.
블럭 상태에서 자식을 죽이면 다시 작동하는건 소스상으로 영원히 대기해야하는 부모가 외부적인요건으로 자식이 죽어서 대기 상태가 풀려서 다음 일을 진행하기 때문일거라고 보이는데요.
물론, 자식이 왜 블럭 상태가 되는지는 모르겠지만요.
제가 올린 처음 두개의 코드를 실행해서 화면에 찍히는 것을 올려주실 수 있나요?
댓글 달기