Kill 함수처럼 시그널을 보낼 수 있는 함수를 사용해서 다른 프로세스에 시그널을 보내는 경우,
사용자가 CTRL+C와 같이 인터럽트 키를 입력한 경우가 존재한다.
시그널 처리방법
시그널이 프로세스에 도달하면 프로세슨느 각 시그널에 지정된 기본 동작을 수행한다.
대부분의 기본 동작은 프로세스를 종료하는 것이다.
하지만 프로그래밍을 통해 시그널을 무시하거나,
시그널 처리를 위한 함수(핸들러)를 지정할 수 있고
블럭처리를 할 수 있다.
시그널의 종류
시그널의 종류
시그널 보내기
kill -9 3255
kill -[시그널번호] PID
kill은 프로세스에 시그널을 보내는 명령어이다.
3255번 프로세스에 9번 시그널(SIGKILL)을 보내면 프로세스가 강제 종료 된다.
#include<sys/types.h>#include<signal.h>intkill(pid_t pid, int sig);
import os
import signal
os.kill(pid, sig) # signal.SIGALRM와 같이 시그널 변수를 사용한다.
os.killpg(pgid, sig) # 프로세스 그룹에 시그널을 보낼 때 사용한다.
pid > 0 인 경우 pid로 지정한 프로세스에 시그널을 발송한다.
pid < -1 일 때는 프로세스 그룹 ID가 pid의 절대값인 프로세스 그룹에 속하고
시그널을 보낼 권한을 가지고 있는 모든 프로세스에 시그널을 발송한다.
pid == 0 인 경우
특별한 프로세스를 제외하고 프로세스 그룹ID가 시그널을 보내는 프로세스의 프로세스 그룹 ID과 같은
모든 프로세스에게 시그널을 발송한다.
pid == -1 인 경우
시그널을 보내는 프로세스의 유효 사용자 ID가 root가 아니라면,
특별한 프로세스를 제외하고 프로세스의 실제 사용자ID가
시그널을 보내는 프로세스의 유효 사용자ID와 같은 모든 프로세스에 시그널을 발송한다.
#include<unistd.h>#include<signal.h>#include<stdio.h>intmain(){
printf("Before SIGCONT Signal to parent.\n");
kill(getppid(), SIGCONT);
printf("Before SIGQUIT Signal to me.\n");
kill(getpid(), SIGQUIT);
printf("After SIGQUIT Signal.\n");
return0;
}
#결과
root@ac265c3fef72:/source/signal# ./ex8_1
Before SIGCONT Signal to parent.
Before SIGQUIT Signal to me.
Quit
시그널을 비트 마스크(128bit)로 표현한다. 각 비트가 특정 시그널과 1:1로 연결된다.
비트 값이 1이면 해당 시그널이 설정된 것이고, 0이면 시그널 설정이 안된 것이다.
시그널 처리 함수
//sigemptyset(3)을 활용하여 시그널 집합에서 모든 시그널을 0으로 설정할 수 있다.intsigemptyset(sigset_t *set);
//시그널 집합에서 모든 시그널을 1로 설정intsigfillset(sigset_t *set);
//시그널 집합에 시그널 설정 추가intsigaddset(sigset_t *set, int signo);
//시그널 집합에 시그널 설정 삭제intsigdelset(sigset_t *set, int signo);
//시그널 집합에서 시그널이 포함되어 있는지 확인intsigismember(sigset_t *set, int signo);
#include<unistd.h>#include<signal.h>#include<stdlib.h>#include<stdio.h>intmain(){
sigset_t st;
sigemptyset(&st);
sigaddset(&st, SIGINT);
sigaddset(&st, SIGQUIT);
if(sigismember(&st, SIGINT))
printf("SIGINT is setting.\n");
//__val은 시스템 환경마다 다른 변수 이름을 사용해야한다 ubuntu에서는 __val 사용printf("** Bit Pattern: %x\n", st.__val[0]);
return0;
}
실행 결과
SIGINT is setting.
** Bit Pattern: 6
sigchild로 자식 프로세스 정리
#include<unistd.h>#include<signal.h>#include<stdlib.h>#include<stdio.h>staticvoidsig_child(int);
intmain(){
pid_t pid;
int i;
signal(SIGCHLD, sig_child);
pid = fork();
//자식인 경우 pid가 0이므로 sleep후 종료한다if(pid == 0){
sleep(1);
exit(0);
}
while(1){
//부모인 경우 계속 while문을 돈다.
i = i;
sleep(1);
}
return0;
}
staticvoidsig_child(int signo){
pid_t pid; int status;
//wait함수로 자식프로세스 종료를 기다린다.
pid = wait(&status);
printf("child %d finished\n %d", pid, status);
}
SIGFPE로 divide by zero 에러 처리
#include<unistd.h>#include<signal.h>#include<stdlib.h>#include<stdio.h>staticvoidsig_fpe(int);
intmain(){
pid_t pid;
int i;
signal(SIGFPE, sig_fpe);
i = i/0;
}
staticvoidsig_fpe(int signo){
pid_t pid; int status;
printf("Divide by 0 Error\n");
exit(1);
}
기타 시그널 처리 함수
// 시그널 정보 출력// s에 지정한 문자열을 붙여 정보 출력voidpsignal(int sig, constchar *s);
//인자로 받은 시그널을 가리키는 이름을 문자열로 리턴char *strsignal(int sig);
//시그널 블록킹과 해제//인자로 받은 시그널을 시그널 마스크에 추가하거나 해제한다intsighold(int sig);
intsigrelse(int sig);
#include<unistd.h>#include<signal.h>#include<stdlib.h>#include<stdio.h>voidhandler(int signo){
char *s;
s = strsignal(signo);
printf(stdout, "Received Signal : %s\n", s);
}
intmain(){
if (sigset(SIGINT, handler) == SIG_ERR){
perror("sigset");
exit(1);
}
sighold(SIGINT);
pause();
return0;
}