C 시그널 처리는 C 프로그래밍 언어에서 실행 중인 프로그램이 운영 체제 혹은 다른 프로세스로부터 발생하는 비동기 이벤트(시그널)를 감지하고, 해당 시그널에 대응하는 함수를 실행하도록 하는 메커니즘이다. 시그널은 주로 프로세스 종료, 중단, 알람, I/O 오류 등과 같은 시스템 레벨 사건을 알리기 위해 사용되며, POSIX 표준을 기반으로 한 대부분의 UNIX‑like 운영 체제에서 지원된다.
1. 개념 및 역사
- 시그널(signal)은 프로세스에게 특정 사건이 발생했음을 알리는 인터럽트와 유사한 메커니즘이다.
- 초기 C 표준(C89)에서는
signal()함수만을 정의했으며, 이후 POSIX.1‑2001 표준에 따라 보다 정교한sigaction()인터페이스가 추가되었다. - C 표준 라이브러리(
<signal.h>)는 시그널 정의와 기본적인 처리를 제공하지만, 실제 시그널 동작은 운영 체제에 의존한다.
2. 주요 헤더와 타입
#include <signal.h>
typedef void (*sighandler_t)(int);// 시그널 핸들러 함수 포인터 타입 (POSIX)typedef sig_atomic_t// 시그널 핸들러와 메인 코드 간에 안전하게 공유 가능한 정수형
3. 핵심 함수
| 함수 | 설명 | 비고 |
|---|---|---|
void (*signal(int sig, void (*func)(int)))(int); |
지정된 시그널 sig에 대해 핸들러 func를 등록한다. 기존 핸들러 포인터를 반환한다. |
표준 C, 구현에 따라 동작이 제한적 |
int raise(int sig); |
현재 프로세스 내에서 시그널 sig를 발생시킨다. |
테스트 용도 또는 프로그램 자체에서 시그널을 트리거 |
int kill(pid_t pid, int sig); |
지정된 프로세스(pid)에 시그널 sig를 전송한다. |
<unistd.h>에 정의, POSIX |
int sigaction(int sig, const struct sigaction *act, struct sigaction *oldact); |
시그널 핸들러를 보다 상세히 정의한다. sigaction 구조체를 통해 블록 마스크, 플래그, 대체 핸들러 등을 지정 가능. |
POSIX 권장 방식 |
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); |
현재 프로세스의 시그널 마스크를 변경한다. | 시그널 차단/해제에 사용 |
int sigpending(sigset_t *set); |
현재 프로세스에 pending 상태인 시그널 집합을 반환한다. | |
int sigsuspend(const sigset_t *mask); |
지정된 마스크로 일시적으로 차단을 해제하고, 시그널이 도착하면 반환한다. |
4. 시그널 핸들러 작성 시 주의사항
-
비동기 안전성(Async‑safety)
시그널 핸들러 내부에서는printf(),malloc()등 비동기 안전이 보장되지 않은 함수는 사용하면 안 된다. POSIX는async-signal-safe함수 목록을 정의한다(예:write(),_exit(),signal(),sig_atomic_t변수 접근 등). -
sig_atomic_t사용
핸들러와 메인 코드 사이에 데이터를 공유할 경우volatile sig_atomic_t타입을 사용해 원자성을 확보한다. -
재진입 방지
동일 시그널이 다시 발생했을 때 핸들러가 중첩 실행되지 않도록sigaction의SA_RESTART혹은SA_RESETHAND플래그를 적절히 설정한다. -
시그널 마스크
특정 구간에서 시그널을 차단하고 싶을 때sigprocmask()혹은pthread_sigmask()(멀티스레드 환경) 를 사용한다.
5. 예제 코드
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
volatile sig_atomic_t quit = 0;
void handle_sigint(int sig)
{
(void)sig; // 사용하지 않음 표시
quit = 1; // 메인 루프에 종료 신호 전달
}
int main(void)
{
struct sigaction sa;
sa.sa_handler = handle_sigint;
sigemptyset(&sa.sa_mask); // 시그널 마스크 비우기
sa.sa_flags = 0; // 기본 플래그
if (sigaction(SIGINT, &sa, NULL) == -1) {
perror("sigaction");
return 1;
}
printf("Ctrl‑C를 눌러 종료합니다...
");
while (!quit) {
pause(); // 시그널 대기
}
printf("프로그램을 종료합니다.
");
return 0;
}
설명
SIGINT(Ctrl‑C) 발생 시handle_sigint가 호출되어quit플래그를 설정한다.while루프에서는pause()를 사용해 시그널이 올 때까지 대기한다.sigaction을 사용했으므로 시그널 핸들러는 비동기 안전하게 동작한다.
6. 플랫폼별 차이
| 플랫폼 | 지원 시그널 | 비고 |
|---|---|---|
| Linux (glibc) | POSIX 전부 + 실시간 시그널(SIGRTMIN~SIGRTMAX) |
sigaction 권장 |
| macOS | POSIX 시그널 (실시간 시그널 미지원) | signal도 동작하지만 sigaction이 안전 |
| Windows | 제한적인 C 시그널(SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM) |
실제 시그널 메커니즘이 없으며, C 런타임이 에뮬레이션 |
| RTOS (예: VxWorks) | 구현에 따라 다름 | 실시간 시그널 지원 여부가 주요 차이점 |
7. 관련 주제
- 실시간 시그널(Real‑time Signals) – POSIX에서 우선순위와 큐잉을 제공하는 확장 시그널.
- 멀티스레드와 시그널 –
pthread_sigmask,sigwait,sigwaitinfo등으로 스레드별 시그널 처리. - 프로세스 제어 –
fork(),exec(),waitpid()와 시그널 연계. - 시그널 안전 함수 – POSIX가 정의한
async-signal-safe함수 목록.
8. 참고 문헌
- ISO/IEC 9899:1999 (C99) –
<signal.h>규격. - POSIX.1‑2008 – 신호(
Signal) 인터페이스 정의. - Stevens, W. R., & Rago, S. (2013). Advanced Programming in the UNIX Environment (3rd ed.). Addison‑Wesley.
- The Open Group Base Specifications Issue 7 –
sigaction,sigprocmask등.
위 내용은 C 언어에서 시그널을 처리하기 위한 핵심 개념·함수·사용법을 포괄적으로 정리한 백과사전 수준의 설명이다.