현생/TCP 소켓 프로그래밍

10-4 시그널 핸들링 - signal [C][LINUX]

푸더기 2022. 1. 27. 20:55
반응형

 

부모 프로세스에서 자식 프로세스의 종료를 계속 확인하기에는 비효율적입니다. 자식 프로세스의 종료를 인식하는 주체는 운영체제이므로 운영체제가 부모 프로세스에게 자식 프로세스의 종료를 알릴 수 있다면 더 효율적일 것입니다.

 

#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(SIGCHLD, exfunc);

예를 들어 자식 프로세스가 종료되면 exfunc 함수를 호출해달라는 상황일 때 signal 함수의 호출은 위와 같이 할 수 있습니다. 이때 exfunc 함수는 매개변수형이 int, 반환형이 void여야 합니다. 

 

 

#include<unistd.h>

unsigned int alarm(unsigned int seconds);
// 0 또는 SIGALRM 시그널이 발생하기까지 남아있는 시간 초 단위 반환

위 특정 상황중 SIGALRM에서 alarm 함수가 등장하는데, 전달된 수에 해당하는 시간이 지나서 SIGALRM 시그널이 발생합니다. 만약 0을 인자로 전달하면 이전에 설정된 SIGALRM 시그널 발생 예약이 취소됩니다. 다만 위 함수호출로 시그널 발생을 예약만 해놓고 signal 함수호출을 통해 이 시그널의 함수를 지정하지 않으면 프로세스가 종료됩니다.

 

#include<stdio.h>
#include<unistd.h>
#include<signal.h>

void timeout(int sig){
	if(sig==SIGALRM)
		puts("Time out");
	alarm(2);
}

void keycontrol(int sig){
	if(sig==SIGINT)
		puts("CTRL+C pressed");
}

int main(int argc, char *argv[]){
	int i;
	signal(SIGALRM, timeout);
	signal(SIGINT, keycontrol);
	alarm(2);
	for(i=0; i<3; i++){
		puts("wait...");
		sleep(100);
	}
	return 0;
}

signal의 예제코드입니다. 이 함수를 실행하면 wait를 출력하고 100초를 기다려야하는데, 얼마 안 기다리고 Time out을 출력하는 걸 볼 수 있습니다. 이 이유는 시그널 핸들러 호출을 위해 sleep 함수의 호출로 블로킹상태에 있던 프로세스가 깨어났기 때문입니다.

반응형