728x90
- 좀비 프로세스의 소멸2: waitpid함수의 사용
- wait함수의 블로킹이 문제가 된다면 waitpid함수의 호출을 고려하면된다. 이는 좀비 프로세스의 생성을 막는 두 번째 방법이자 블로킹 문제의 해결책이기도하다
- #include<sys/wait.h>
- pid_t waitpid(pid_t pid, int * statloc, int options);
- -> 성공시 종료된 자식 프로세스의 ID(또는 0) 실패시 -1 반환
- pid : 종료를 확인하고자 하는 자식 프로세스의 ID 전달, 이를 대신해서 -1을 전달하면 wait함수와 만찬가지로 임의의 자식 프로세스가 종료되기를 기다린다.
- statloc : wait 함수의 매개변수 statloc과 동일한 의미로 사용된다.
- options 헤더파일 sys/wait.h에 선언된 상수 WNOHANG을 인자로 전달하면 종료된 자식 프로세스가 존재하지 않아도 블로킹 상태에 있지않고 0을 반환하면서 함수를 빠져나온다.
- waitpid.c
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char* argv[])
{
int status;
pid_t pid = fork();
if(pid == 0)
{
// 자식 프로세스의 종료를 늦추기 위해서 sleep 함수를 호출하고있다. 이로 인해서
// 약 15초간의 지연이 생긴다.
sleep(15);
return 24;
}
else
{
// while문 내에서waitpid 함수를 호출하고있다.
// 세번째인자로WNOHANG을 전달하였으니, 종료된 자식 프로세스가 없으면 0을 반환한다.
while(!waitpid(-1, &status, WNOHANG))
{
sleep(3);
puts("sleep 3sec.");
}
if(WIFEXITED(status))
printf("Child send %d \n", WEXITSTATUS(status));
}
return 0;
}
- 10-3 시그널 핸들링
- 문제 : 자식프로세스가 언제 종료될지 알고 waitpid 함수를 계속 호출할까?
- 정답 : 운영체제가 알려준다.
- 운영체제야! 네가 좀 알려줘
- 자식 프로세스 종료의 인식주체는 운영체제이다. 따라서 운영체제가 열심히 일하고 있는 부모 프로세스에게 다음과 같이 이야기 해줄 수 있다면 효율적인 프로그램의 구현이 가능하다.
- 어이 부모 프로세스 네가 생성한 자식 프로세스가 종료되었어!
- 그러면 부모 프로세스는 하던 일을 잠시 멈추고 자식 프로세스의 종료와 관련된 일을 처리하면 된다. 이러한 시나리오의 프로그램 구현을 위해서 "시그널 핸들링(signal Handling)"이라는 것이 존재한다. 여기서 "시그널"은 특정상황이 발생했음을 알리기 위해 운영체제가 프로세스에게 전달하는 메시지를 의미한다. 그리고 그 메시지에 반응해서 메시지와 연관된 미리 저으이된 작업이 진행되는 것을 가리켜 "핸들링" 또는 "시그널 핸들링"이라 한다.
- 시그널과 signal 함수
- 프로세스: 야 운영체제! 내가 생성한 자식 프로세스가 종료되면 zombie_handler라는 이름의 함수 좀 호출해 주라
- 운영체제: 그래! 그럼네가 생성한 자식 프로세스가 종료되면, 네가 말한 zombie_handler라는 이름의 함수를 내가 대신 호출해줄 테니 그 상황에서 실행해야 할 문장들을 그 함수에 잘 묶어둬
- 위의 대화중에서 프로세스가 한 이야기가 "시그널 등록"에 해당된다. 즉 프로세스는 자식 프로세스의 종료라는 상황 발생시 특정 함수의 호출을 운영체제에게 요구하는 것이다. 이 요구는 다음 함수의 호출을 통해서 이뤄진다(때문에 이 함수를 시그널 등록 함수라 표현한다)
- #include <signal.h>
- void (*signal(int signo, void (*func)(int)))(int);
- -> 시그널 발생시 호출되도록 이ᅟ전에 등록된 함수의 포인터 반환
- 위의 함수는 반환형이 포인터이다보니 선언이 다소 복잡해 보인다. (참고로 함수포인터를 모르면 지금부터설명하는 내용의 이해가 불가능하다) 지금은 학습의 편의를 위해 필자가 위의 함수 선언을 다음과 같이 정리해놓겠다.
- 함수이름 : signal
- 매개변수 선언 : int signo, void(*func)(int)
- 반환형 : 매개변수형이 int 이고 반환형이 void인 함수 포인터
- 위 함수를 호출하면서 첫 번째 인자로 특정 상황에 대한 정보를 두번째 인자로 특정상황에서 호출될 함수의 주소값(포인터)을 전달한다. 그러면 첫 번째 인자를 통해 명시된 상황 발생시 두번째 인자로 전달된 주소값의 함수가 호출된다. 참고로 signal함수를 통해서 등록가능한 특정상황과 그 상황에 할당된 상수 몇몇을 정리해보면 다음과 같다.
- SIGALRM : alarm함수호출을 통해서 등록된 시간이 된 상황
- SIGINT : CTRL + C가 입력된 상황
- SIGCHLD: 자식 프로세스가 종료된 상황
- 자 그럼 다음 요청에 해당하는 signal함수의 호출문장을 만들어보겠다.
- 자식프로세스가종료되면 mychild 함수를 호출해 달라
- 이때 ᅟmychild함수는 매개변수형이 int이고 반환형이void이어야 한다. 그래야 signal함수의 두번째 전달인자가 될수 있다. 그리고 자식 프로세스가 종료된 상황은 상수 SIGCHLD로 정의되어 있으니 이것이 signal 함수의 첫 번째 인자가 되어야 한다. 즉 signal함수의 호출문장은 다음과 같이 구성하면된다.
- signal(SIGCHLD, mychild);
- 그럼 이번에는 다음 두가지 요청에 해당하는 signal함수의 호출문장을 각각 만들어 보겠다.
- alarm 함수호출을 통해서 등록된 시간이 지나면 timeout함수를 호출해줘
- CTRL+C 가 입력되면 keycontrol함수를 호출해줘
- 이들 각각의 상황에 할당된 상수의 이름이 SIGALRM, SIGINT이니 다음과 같이 signal함수의 호출 문장을 구성하면된다.
- signal(SIGALRM, timeout);
- signal(SIGINT, keycontrol);
728x90
'책 > 윤성우 TCPIP' 카테고리의 다른 글
10-03 : 시그널 핸들링 (3) ~ 10-04 멀티태스킹 기반의 다중접속 서버(1) (0) | 2020.12.20 |
---|---|
10-03 : 시그널 핸들링 (2) (0) | 2020.12.19 |
10-1 프로세스의 이해와 활용 (0) | 2020.12.15 |
09-2 : SO_REUSEADDR (3) (0) | 2020.12.14 |
09-2 : SO_REUSEADDR (2) (0) | 2020.12.13 |