SIGNAL이란?Signal은 유닉스, 유닉스 계열, POSIX 호환 운영체제에 쓰이는 제한된 형태의 프로세스 간 통신이다. 프로세스나 동일 프로세스 내의 특정 스레드로 전달되는 비동기식 통보인 것이다.
프로세스가 시그널을 받게 되면 :
1. 시그널에 해당되는 기본 동작을 하거나
2. 그 시그널을 무시하거나
3. 사용자가 정의한 함수를 통해 동작 방식을 바꿀 수 있다.
SIGNAL 보내기실행 중인 프로세스의 제어 터미널에서 특정 키 조합을 입력하면 시스템이 특정 신호를 보낸다.
ctrl+c
INT 신호 (SIGINT)를 내보낸다.ctrl+z
TSTP 신호 (SIGTSTP)를 내보낸다.ctrl+\
QUIT 신호 (SIGQUIT)를 내보낸다.ctrl+t
INFO 신호 (SIGINFO)를 내보낸다.현대 운영체제에서 이러한 기본 키 조합들은
stty명령으로 변경할 수 있다.
SIGNAL 종류SIGHUP
SIGINT
ctrl_c)인터럽트란?
- CPU로 하여금 현재 진행중인 프로그램 처리를 중단하고 다른 프로그램을 처리하도록 요구하는 매커니즘.
- 외부 장치와 상호작용을 위해 반드시 필요하다.
SIGQUIT
ctrl+\)SIGKILL
SIGSEGV
SIGSTOP
ctrl+z)
ctrl+d
EOF를 의미- 시그널이 아니다.
- stdin pipe를 닫는다. (
read(STDIN) return 0)
리눅스 상에서
kill -l명령어를 입력하면 모든 시그널의 종류를 알 수 있다.
SIGNAL 성질비신뢰성
대기하지 않음
프로세스를 직접 생성해서 시그널을 주는 예시 :
#include <signal.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
printf("give signal...\n");
sleep(30);
exit(0);
}
위 코드를 컴파일 후 실행하면 30초간 프로그램이 실행될 것이다.
이 상태에서 ctrl+c를 누르게 되면 SIGINT 신호를 보내게 된다. 기본동작은 종료이므로 프로세스가 종료하게 된다.
또는 kill -시그널번호 프로세스 id를 통해서 시그널을 보낼 수도 있다. 즉, SIGINT를 보내려면 kill -2 pid 또는 kill -SIGINT pid를 통해서 SIGINT를 보낼 수 있다.
우리는 이 시그널을 제어하고 싶다. 그래서 리눅스는 signal 핸들러를 제공한다.
signal 함수형식 : void (*signal(int signum, void (*handler)(int)))(int);
첫 번째 인자 signum은 시그널을 발생시키는 번호이다. (SIGINT는 2번이었다.)
아니면 매크로를 쓸 수도 있다. SIGINT가 그대로 매크로에 정의되어 있다.
두 번째 인자 handler라는 함수 포인터에 함수를 인자로 주게 됨녀 시그널을 받았을 때 그 함수가 호출된다.
SIGINT 예시 :
#include <signal.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void interruptHandler(int sig)
{
printf("this program will be exited in 3 seconds...\n");
sleep(3);
exit(0);
}
int main()
{
signal(SIGINT, interruptHandler);
printf("input ctrl+c\n");
while (1);
}
컴파일 후 실행하고 ctrl+c를 입력하면 메세지와 함께 3초 후 프로그램이 종료된다.
SIGSTOP 예시 :
#include <signal.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void stopHandler(int sig)
{
printf("this program will be exited in 3 seconds...\n");
sleep(3);
exit(0);
}
int main()
{
signal(SIGSTOP, stopHandler);
printf("input ctrl+z\n");
while (1);
}
ctrl+z를 입력하여 SIGSTOP을 보내면 그냥 멈춰버린다. 핸들링되지 않는 것이다. SIGKILL과 SIGSTOP은 사용자가 절대 제어할 수 없다. 어떤 이유로 인해 프로세스를 무조건 죽여야하는 경우가 있다고 해보자. 만약 좀비프로세스를 계속해서 생성하는 프로세스가 있는데 이 프로세스를 죽이지 못하면 안된다. 그래서 2개는 핸들링을 하지 못하는 것이다.
또한 핸들러에 전달인자 sig는 시그널의 종류를 나타낸다.
그렇기 때문에 시그널의 종류에 따라 처리할 수 있다 :
#include <signal.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void signalHandler(int sig)
{
if (sig==SIGINT)
{
printf("this program will stop in 3 seconds...\n");
sleep(3);
exit(0);
}
if (sig==SIGQUIT)
{
printf("signal SIGQUIT\n");
}
}
int main()
{
signal(SIGINT, signalHandler);
signal(SIGQUIT, signalHandler);
printf("input ctrl+c or ctrl+\\ \n");
while (1);
}
프로그램을 실행하여 ctrl+\를 입력해서 SIGQUIT신호를 보내도 종료하지 않고, SIGINT를 보냈을 때 3초안에 종료된다.
참고 사이트 :