시그널(Signal)이란?
시그널(Signal)은 프로세스에게 특정 사건이 시스템 내에서 발생했음을 알리는 작은 메시지. 시그널은 운영체제(OS)가 프로세스의 흐름을 예외적으로 중단하고, 특정 처리를 수행하도록 요청하는 방식입니다.
- 시그널의 필요성
- 외부에서 프로세스 강제 종료 요청
- 프로세스 간 통신 및 동기화
- 비정상적 사건 알림 (메모리 접근 위반 등)
시그널의 종류 및 대표적 예시
리눅스는 약 30여가지의 시그널을 지원, 대표적인 예시:
| 시그널 | 기본 동작 | 설명 |
|---|---|---|
| SIGINT (2) | 종료 | 키보드 인터럽트 (Ctrl+C) |
| SIGKILL (9) | 종료 | 강제 종료 (무조건 종료) |
| SIGSEGV (11) | 종료 및 코어덤프 | 잘못된 메모리 접근 |
| SIGALRM (14) | 종료 | 타이머 알람 |
| SIGTERM (15) | 종료 | 소프트웨어 종료 요청 |
| SIGCHLD (17) | 무시 | 자식 프로세스 상태 변경 (종료/정지) |
| SIGSTOP (19) | 정지 | 프로세스 실행 정지 (Ctrl+Z) |
| - SIGKILL과 SIGSTOP은 프로그램에서 무시하거나 재정의할 수 없음 |
시그널 처리 과정 및 용어
시그널 처리는 크게 발송(Sending)과 수신(Receiving) 두 단계로 나뉨
① 시그널 발송 (Sending)
시그널 발송은 커널이 프로세스의 상태를 업데이트하는 형태로 이루어짐
커널이 시스템 이벤트감지(0으로 나누기, 자식 프로세스 종료 등)- 또는
프로세스가 명시적으로kill() 함수를 호출해 다른 프로세스에게 시그널 발송
② 시그널 수신 (Receiving)
시그널 수신 시, 커널이 해당 프로세스에 강제로 특정 행동을 취하도록 함. 수신된 프로세스는 시그널을 무시하거나, 기본 동작을 수행하거나, 미리 정의된 핸들러 함수를 호출할 수 있음
- 프로세스가 시그널을 수신하면, 즉시 실행을 중단하고 해당 시그널 핸들러(signal handler)를 실행
- 핸들러 실행이 끝나면 프로세스의 원래 실행 흐름으로 복귀
파생 개념
- Pending signal: 발송되었지만 아직 수신되지 않은 시그널
- Blocked signal: 프로세스가 수신을 일시적으로 차단한 시그널
시그널 보내기 (Sending Signals)
리눅스에서는 다음과 같은 방법으로 시그널을 보낼 수 있음
- kill 명령어 사용
kill -9 15213 # PID가 15213인 프로세스를 강제 종료(SIGKILL)
- 키보드로부터 입력
- Ctrl+C → SIGINT 발생
- Ctrl+Z → SIGTSTP 발생 (프로세스 일시정지)
- 프로그램에서 함수로 호출
kill(pid, SIGKILL); // 프로세스에 SIGKILL 시그널 전달
alarm(10); // 10초 후 자신에게 SIGALRM 시그널 전달
시그널 받기 및 처리 (Receiving Signals)
시그널을 받은 프로세스는 아래 동작 중 하나를 수행
- 기본 동작(terminate, ignore, stop 등)을 수행
- 사용자 정의 핸들러(signal handler)를 호출하여 특정 처리를 수행
- 시그널 무시(SIG_IGN) 또는 기본 동작으로 복원(SIG_DFL)
시그널 핸들러는 다음과 같이 설치:
signal(SIGINT, handler); // SIGINT에 대한 핸들러 등록
- 핸들러 함수 예시:
void handler(int sig) {
printf("SIGINT 시그널이 발생했습니다!\n");
exit(0);
}
시그널 블로킹(차단)과 언블로킹(해제)
프로세스는 특정 시그널 수신을 일시적으로 차단할 수 있음
- sigprocmask() 함수
sigset_t mask, prev_mask;
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigprocmask(SIG_BLOCK, &mask, &prev_mask); // SIGINT 블로킹
// 차단된 영역에서의 처리
sigprocmask(SIG_UNBLOCK, &mask, NULL); // SIGINT 언블로킹
sigprocmask(SIG_SETMASK, &prev_mask, NULL); // 이전 상태로 복원(간접적/암시적인 언블록)
- sigset_t으로 차단 집합 만들고, SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK 옵션 사용
시그널 핸들러 작성 시 주의점
핸들러는 주 프로그램과 동시에(concurrently) 실행되므로 안전하게 작성
간단한 로직만 포함할 것- printf, malloc 등 일반 함수 호출 자제 → 대신
Async-signal-safe 함수(write, exit, sigatomic_t 등)만 사용 공유 데이터를 다룰 때는 임시적으로모든 시그널을 차단할 것- 전역 변수는
volatile, 플래그는sig_atomic_t로 선언
파생 개념과 연결
- 프로세스 그룹(Process Group): 여러 프로세스를 그룹으로 묶어서 시그널을 보내거나 관리할 때 사용
- 시스템 콜(System Call): 시그널을 통해 커널과 사용자 프로세스 간 통신 가능(예: SIGCHLD)
- 동시성 문제(Concurrency): 시그널과 메인 프로그램의 동시 실행은 경쟁 상태(race condition)를 일으킬 수 있으므로, 신중한 설계와 동기화가 필요
요약 정리
- 시그널은 프로세스가 시스템 이벤트를 처리하도록 하는 커널과 프로세스 간 통신 수단
- 특정 시그널은 무시하거나 재정의할 수 없으며, 시그널 처리기는 안전하고 간단하게 작성해야 함
- 시그널은 시스템의 다양한 상황 처리(강제 종료, 예외 처리, 프로세스 관리 등)에 필수적이며, 프로세스 관리, 시스템콜, 동시성 등 여러 개념과 밀접히 연결됨
728x90
'CS:APP' 카테고리의 다른 글
| 예외상황 (0) | 2025.08.10 |
|---|---|
| 실행 가능 목적파일의 로딩 (0) | 2025.08.09 |
| ELF, Executable and Linkable Format (재배치 가능 목적파일) (0) | 2025.08.08 |
| 컴파일러 드라이버 (0) | 2025.08.04 |
| 함수는 추상화의 결과다 - CS:APP 3.7 프로시저 호출 (0) | 2025.04.08 |