
signal() 함수의 불안정함(시스템별 동작 차이)을 해결하고, 핸들러 실행 중 '다른 시그널 차단' 등 정교한 제어가 가능한 표준 함수
sigaction을 써야 하는 이유sa_mask)SA_SIGINFO)C
#include <signal.h>
struct sigaction {
void (*sa_handler)(int); // 핸들러 함수 포인터
void (*sa_sigaction)(int, siginfo_t *, void *); // 고급 핸들러
sigset_t sa_mask; // 핸들러 실행 중 블록할 시그널들
int sa_flags; // 동작 옵션
void (*sa_restorer)(void); // 내부용 (사용 안 함)
};
void advanced_handler(int signo, siginfo_t *info, void *context) {
printf("시그널: %d\n", signo);
printf("보낸 프로세스 PID: %d\n", info->si_pid);
printf("보낸 UID: %d\n", info->si_uid);
}
sa.sa_sigaction = advanced_handler;
sa.sa_flags = SA_SIGINFO; // 이 플래그 필수
이 예제는 SIGINT(Ctrl+C)를 처리하는 도중에 SIGQUIT(Ctrl+\)가 들어와도 무시(블록)하고, 하던 일을 마친 뒤에 처리하는 안정성을 보여줍니다.
C
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
void my_handler(int signo) {
printf("\n[Handler] 시그널 %d번 처리 시작 (3초 소요)...\n", signo);
printf("[Handler] 이 동안에는 Ctrl+\\ (SIGQUIT)을 눌러도 대기합니다.\n");
for (int i = 0; i < 3; i++) {
printf("... 처리 중 %d\n", i + 1);
sleep(1);
}
printf("[Handler] 처리 완료.\n");
}
int main() {
struct sigaction act;
// 1. 핸들러 함수 지정
act.sa_handler = my_handler;
// 2. 마스크 설정 (핸들러 실행 중 막을 시그널)
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask, SIGQUIT); // SIGINT 처리 중엔 SIGQUIT을 블록함!
// 3. 플래그 설정
// SA_RESTART: 시그널 처리 후 중단된 시스템 콜(read, write 등)을 자동 재시작
act.sa_flags = SA_RESTART;
// 4. 등록
if (sigaction(SIGINT, &act, NULL) == -1) {
perror("sigaction");
exit(1);
}
printf("PID: %d\n", getpid());
printf("Ctrl+C를 눌러보세요. 핸들러 실행 중에 Ctrl+\\도 눌러보세요.\n");
while (1) {
printf("Main Loop...\n");
sleep(1);
}
return 0;
}


Ctrl+C 입력: my_handler가 실행되어 "처리 중 1, 2, 3"을 출력하기 시작함.Ctrl+\ 입력:signal() 함수였다면: 핸들러가 멈추고 즉시 Quit (core dumped) 되며 죽음.sigaction() 결과: 아무 반응 없음 (블록됨). my_handler가 "처리 완료" 메시지를 띄우고 리턴된 직후에 Quit 시그널이 처리되어 종료됨.sa_flags)
0: 기본 동작.SA_RESTART: 시그널 때문에 끊긴 read(), write() 등을 에러(EINTR) 내지 않고 자동으로 재시작해줌. (매우 유용).SA_SIGINFO: 핸들러 함수 파라미터를 확장하여, 송신자 PID나 데이터를 받을 수 있게 함. (sa_handler 대신 sa_sigaction 사용).reference : https://reakwon.tistory.com/215#google_vignette