-
[시스템프로그래밍] Wait시스템프로그래밍 2023. 12. 14. 00:38
https://scwcart.tistory.com/entry/Process-Management
Process Management
https://scwcart.tistory.com/entry/Process Process 앞선 글들에서 다른 개념들을 설명하면서 '프로그램'과 '프로세스' 두 개의 단어가 계속 뒤섞여 나왔습니다. 프로그램은 뭐고 프로세스는 뭘까요? 결론부터
scwcart.tistory.com
앞 글에서 부모 프로세스는 자식 프로세스의 실행이 끝날 때까지 wait()로 기다린다고 했습니다.
그럼 wait() 시스템 콜에 대해 좀 더 자세히 알아볼까요?
Wait()
wait() 시스템 콜은 부모 프로세스가 자식 프로세스 실행이 끝날 때까지 기다리도록 하는 역할을 합니다.
pid = wait(&status) 형태로 wait()을 쓸 수 있는데,
&status 인수를 통해 자식 프로세스가 exit()에서 전달한 종료 상태 값을 받을 수 있습니다.
wait()을 사용한 프로그램을 하나 짜 보도록 하겠습니다.
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/wait.h> #define DELAY 2 int main() { int newpid; void child_code(), parent_code(); printf("before: my pid is %d\n", getpid()); if ( (newpid = fork()) == -1 ) //fork 실패 -> -1 반환 perror("fork"); else if ( newpid == 0 ) //child process: 2초 delay child_code(DELAY); else //parent process: child 종료 후 종료 parent_code(newpid); return 0; } void child_code(int delay) { printf("child %d here. will sleep for %d seconds\n", getpid(), delay); sleep(delay); printf("child done. about to exit\n"); exit(17); } void parent_code(int childpid) { int wait_rv; wait_rv = wait(NULL); printf("done waiting for %d. Wait returned: %d\n", childpid, wait_rv); }
위 코드에서 자식 프로세스는 2초 기다렸다가 exit()을 호출합니다.
exit(17)은 자식 프로세스가 exit()했을 때 종료 상태 값으로 17을 반환한다는 뜻입니다.
부모 프로세스는 기다리고 있다가 자식 프로세스가 exit()하면 남은 코드를 실행하고 종료합니다.
wait(null)은 자식 프로세스가 종료할 때까지 기다리라는 의미입니다.
코드를 실행시켜 보면
자식 프로세스가 종료된 후에야 부모 프로세스가 종료되는 것을 볼 수 있습니다.
여기서 하나 알고 넘어가야 할 건 exit()으로 실행이 종료되었다고 해서
그 프로세스가 완전히 없어진 게 아니라 zombie 상태로 남아 있습니다.
기다리던 부모 프로세스가 wait() 상태에서 자식 프로세스가 종료됨을 확인하고 깨어나면서
zombie 프로세스(자식)에 할당되어 있던 리소스가 전부 해제되고 완전히 없어집니다.
아무튼 이 코드에서의 핵심은 2가지입니다.
1) wait()은 자식 프로세스가 종료될 때까지 부모 프로세스의 실행을 막습니다.
즉 synchronization의 역할을 수행합니다.
2) wait()은 exit()을 호출한 자식 프로세스의 PID를 반환합니다.
따라서 두 개의 다른 원격 DB로부터 데이터를 통합하는 등의 프로그램에서 이 속성을 활용해 효과적인 프로그래밍이 가능합니다.
waitdemo1.c에서는 wait(&status)에서 &status 자리에 null을 넣었습니다.
하지만 wait()은 해당 status 값을 통해 자식 프로세스가 어떻게 종료되었는지 알려 줄 수 있습니다.
시스템이 충돌하거나 비정상적으로 종료된 core dump 상황 같은 에러 상황에서 이런 특성은 효과적으로 이용될 수 있겠죠?
그럼 wait()로 종료 상태 값을 받아 보도록 하겠습니다.
위 코드에서 부모 프로세스 부분(parent_code()) 코드만 수정하면 됩니다.
void parent_code(int childpid) { int wait_rv; int child_status; int high_8, low_7, bit_7; wait_rv = wait(&child_status); printf("done waiting for %d. Wait returned: %d\n", childpid, wait_rv); int mask; printf("Child status: "); for(int i = 15; i >= 0; i--) { mask = 1 << i; printf("%d", child_status & mask ? 1 : 0); if ( i % 8 == 0 ) printf(" "); } printf("\n"); high_8 = child_status >> 8; //1111 1111 0000 0000 low_7 = child_status & 0x7F; //0000 0000 0111 1111 bit_7 = child_status & 0x80; //0000 0000 1000 0000 printf("status: exit=%d, sig=%d, core=%d\n", high_8, low_7, bit_7); }
16bit status 값 중 앞쪽 8비트는 exit 값, 뒤쪽 7비트는 signal, 7번 비트는 core입니다.
비트마스킹한 결과를 보면 아까 자식 프로세스에서 전달했던 status 값 17이 잘 전달된 것을 볼 수 있습니다.
종료 상태 값 표입니다.
17은 user signal로 exit을 의미하네요.
지금까지 한 내용을 정리하면 이렇습니다.
프롬프트에서 명령어를 입력하면 해당 명령어를 읽고 실행하던 중
fork()를 만나면 새로운 자식 프로세스가 생기고,
자식 프로세스는 exec()를 만나 main()을 호출하여 새로운 프로그램을 실행한 뒤 exit()을 호출합니다.
그러면 wait()으로 기다리던 부모 프로세스가 자식 프로세스를 완전히 종료시킨 후
대기 상태에서 재시작 상태로 바뀌어 남은 코드를 실행합니다.
다음 글에서는 이런 과정들을 활용한 shell을 짜 보도록 하겠습니다.
끝!
'시스템프로그래밍' 카테고리의 다른 글
[시스템프로그래밍] Timer (1) 2023.12.16 [시스템프로그래밍] Curses (1) 2023.12.16 [시스템프로그래밍] Process Management (0) 2023.12.13 [시스템프로그래밍] Computer Memory and Program (0) 2023.12.13 [시스템프로그래밍] Process (0) 2023.12.13