특정 이벤트가 발생했을 때 프로세스에게 전달하는 신호입니다.
인터럽트라고 부르기도 합니다.
Inter-Process Communication의 약자로, 실행중인 프로세스간 데이터를 주고받는 기법입니다.
IPC 방법들
프로세스가 특정 시그널을 포착했을 때 수행해야 할 별도의 함수입니다.
signal(signal_no, signal_handler)처럼 사용할 수 있습니다.
커널에 해당 시그널 번호를 감지하고 알려달라고 요청한 후 signal_handler를 콜백함수 처럼 사용 할 수 있습니다.
시그널을 다루기 위해선 집합을 만들어야 합니다.
#include <signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum);
int sigismember(const sigset_t *set, int signum);
//set : 시그널 집합
//return
//호출 성공시 0, 실패시 -1
//단, sigismember는 성공적으로 완료되면 지정된 신호가 지정된 집합의 구성원이면 1을 반환하고 그렇지 않으면 0을 반환합니다.
//유효하지 않거나 지원하지 않는 신호번호는 -1을 리턴합니다. (EINVAL)
sigset_t set;
int result;
sigemptyset(&set);
sigfillset(&set);
sigdelset(&set, SIGALRM);
sigaddset(&set, SIGLRM);
result = sigismember(set, SIGALRM); // &안붙인 이유는 변경시킬 수 없는 const형으로 받기때문임
특정 시그널을 받았을 때 프로세스가 취해야 할 행동을 지정해줍니다.
signum으로 지정한 시그널에 대해 act로 지정한 행동을 취합니다.
새로운 act가 등록되면 기존 act는 oldact에 저장됩니다.
#include <signal.h>
int sigcation(int signum, const struct sigaction *act, struct sigaction *oldact);
함수 설명
signum : 시그널 번호(단, SIGKILL, SIGSTOP은 적용 불가)
act : 프로세스가 지정한 시그널에 대해 취할 행동에 대한 정보
oldact : 이전 시그널에 대한 행동이 저장됨. 보통은 NULL로 입력
반환 값 : 성공시 0, 실패시 -1
struct sigaction {
void (*sa_handler)(int);
void(*sa_sigaction)(int, siginfo_t*, void *);
sigset_t sa_mask;
int sa_flags;
}
sa_handler에서 시그널에 대응하는 행동
sa_sigaction 사용방법
sa_mask란?
봉쇄된 시그널들의 집합
등록된 시그널은 시그널 핸들러가 실행되는 동안 봉쇄(blocking)된다.
blocking : 무시가 아닌, 시그널 핸들러 실행이 완료될 때까지 처리가 미뤄진다.
현재 처리중인 시그널도 봉쇄될 수 있다.
sa_flag란?s
시그널 처리 절차를 수정하는데 사용된다.
" | "(bitwise-OR) 을 사용하여 여러 플래그 사용이 가능하다.
처리 가능 값
- SA_SIGINFO : sa_handler 대신 sa_sigaction을 선택
- SA_NOCLDSTOP : signum이 SIGCHLD일 때 자식 프로세스가 종료되거나 중단되더라도 부모 프로세스는 이를 알려고 하지 않는다.
(자식의 상태에 신경을 안써도 되는 상황)- SA_RESETHAND : signum에 대해 시그널 핸들러를 최초에 한번만 실행하고 그 다음부터는 동일한 시그널에 대해 SIG_DFL에 해당하는 기본적인 동작만 수행한다.
- SA_NODEFER : 시그널 핸들러 내에서 시그널 받는 것을 금지하지 않는다.
(즉, 마스크를 사용하지 않는다.)
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
void int_handler(int signum) {
staitc int num = 0;
printf("SIGINT : %d\n", signum);
printf("int_handler called %d times\n", ++num);
}
int main() {
struct sigaction act; //구조체 선언
act.sa_handler = int_handler; //핸들러 초기화
sigfillset(&act.sa_mask); //sig
sigaction(SIGINT, &act, NULL);
while(1) {
printf("I'm sleep\n");
sleep(1);
if (num > 2) {
act.sa_handler = SIG_DFL; //기본 시그널 설정
sigaction(SIGINT, &act, NULL);
}
}
}
출력 결과물
[ydh@krujyit1 ~/src/program/simple_control_signal]$ ./a.out
I'm sleep
I'm sleep
^CSIGINT : 2
int_handler called 1 times
I'm sleep
^CSIGINT : 2
int_handler called 2 times
I'm sleep
^CSIGINT : 2
int_handler called 3 times
I'm sleep
^C
SIGINT가 2라는 값으로 handler에 전달된 것을 확인할 수 있다.
또한, 전역변수 num을 제어하여 일정 횟수 입력시 종료됨을 확인할 수 있다.