iBetter Books
수정

시그널 이해하기

Ctrl+C를 누르는 순간 터미널은 실행 중인 프로세스에 무언가를 보냅니다. 그 무언가가 바로 시그널입니다. 프로세스는 이 시그널을 받고 "아, 종료 요청이구나"라고 인식하고 멈춥니다. 아니면 무시하거나, 개발자가 설정한 다른 동작을 수행할 수도 있습니다.

시그널은 프로세스 간 비동기 통신의 가장 단순한 형태입니다. 메시지 큐나 소켓처럼 복잡하지 않고, 그저 번호 하나를 보내는 것입니다. 하지만 이 단순함 덕분에 시스템의 모든 곳에서 사용됩니다.

시그널이란 무엇인가

시그널은 운영체제가 프로세스에 보내는 비동기 알림입니다. 사용자 입력(Ctrl+C), 다른 프로세스의 요청(kill 명령어), 또는 시스템 이벤트(자식 프로세스 종료)로 발생합니다.

프로세스는 시그널에 세 가지 방식으로 반응할 수 있습니다.

  1. 기본 동작 수행: 운영체제가 정의한 기본 동작(보통 종료)
  2. 사용자 정의 핸들러 실행: trap으로 등록한 함수 실행
  3. 무시: 시그널을 받았지만 아무것도 하지 않음

단, SIGKILL(9)과 SIGSTOP(19)은 가로채거나 무시할 수 없습니다. 커널이 직접 처리하기 때문입니다.

전체 시그널 목록 확인

kill -l

시스템마다 다소 다르지만 Ubuntu 24.04에서는 64개의 시그널을 지원합니다.

 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL
 5) SIGTRAP      6) SIGABRT      7) SIGBUS       8) SIGFPE
 9) SIGKILL     10) SIGUSR1     11) SIGSEGV     12) SIGUSR2
13) SIGPIPE     14) SIGALRM     15) SIGTERM     16) SIGSTKFLT
17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU
25) SIGXFSZ     26) SIGVTALRM   27) SIGPROF     28) SIGWINCH
29) SIGIO       30) SIGPWR      31) SIGSYS      34) SIGRTMIN
...

주요 시그널 상세 설명

스크립트 작성에서 알아야 할 핵심 시그널들입니다.

SIGINT (2) — Ctrl+C

사용자가 Ctrl+C를 누를 때 터미널이 포그라운드 프로세스 그룹에 보내는 시그널입니다. "인터럽트"라는 이름처럼 실행을 중단시킵니다.

  • 발생 시점: 사용자 Ctrl+C, kill -2 PID
  • 기본 동작: 프로세스 종료
  • 활용: 사용자가 중단했을 때 정리 작업 수행
# Ctrl+C 테스트sleep 100# Ctrl+C 누르면 → ^C (종료)

SIGTERM (15) — 정상 종료 요청

프로세스에 정상 종료를 요청하는 시그널입니다. kill 명령어를 시그널 없이 실행하면 기본으로 보내집니다. 프로세스는 이 시그널을 받으면 뒷정리를 하고 종료할 기회를 갖습니다.

  • 발생 시점: kill PID, kill -15 PID, systemd 서비스 중지
  • 기본 동작: 프로세스 종료
  • 활용: graceful shutdown 구현

SIGKILL (9) — 강제 종료

커널이 프로세스를 즉시 제거합니다. 프로세스가 이 시그널을 처리하거나 무시할 수 없습니다.

  • 발생 시점: kill -9 PID, kill -KILL PID
  • 기본 동작: 즉시 종료 (뒷정리 없음)
  • 활용: SIGTERM으로 종료되지 않는 프로세스 처리

SIGHUP (1) — 터미널 종료

원래는 전화선이 끊겼을 때("hangup") 보내던 시그널입니다. 현대에는 터미널이 닫히면 그 터미널에 연결된 프로세스에 보내집니다. 많은 데몬 프로세스는 SIGHUP을 받으면 종료 대신 설정 파일을 다시 읽는 방식으로 재활용합니다.

  • 발생 시점: 터미널 종료, kill -1 PID
  • 기본 동작: 프로세스 종료
  • 활용: 데몬 설정 리로드 (nginx: kill -HUP $(cat /run/nginx.pid))

SIGUSR1 (10), SIGUSR2 (12) — 사용자 정의

운영체제가 의미를 정하지 않은 자유로운 시그널입니다. 개발자가 원하는 목적으로 사용할 수 있습니다.

  • 발생 시점: kill -USR1 PID, kill -USR2 PID
  • 기본 동작: 프로세스 종료
  • 활용: 통계 출력, 로그 레벨 변경, 상태 덤프 등 사용자 정의 기능
# 예: SIGUSR1을 받으면 현재 통계를 출력하는 스크립트trap 'print_stats' USR1print_stats() {    echo "처리 완료: $count건" >> stats.log}

SIGCHLD (17) — 자식 프로세스 종료

자식 프로세스가 종료되거나 정지/재개될 때 부모 프로세스에 보내집니다.

  • 발생 시점: 자식 프로세스 상태 변경 시 자동 발생
  • 기본 동작: 무시 (부모가 직접 처리)
  • 활용: 비동기 자식 프로세스 종료 감지

SIGSTOP (19) vs SIGTSTP (20)

  • SIGSTOP: 처리 불가, 즉시 정지. kill -STOP PID
  • SIGTSTP: 처리 가능, Ctrl+Z. 쉘이 보내는 대화형 정지 요청

SIGCONT (18) — 재개

정지된 프로세스를 재개합니다. bg, fg 명령어가 내부적으로 이 시그널을 보냅니다.

시그널 처리 가능/불가능 표

시그널 번호 처리 가능 무시 가능
SIGINT 2 가능 가능
SIGTERM 15 가능 가능
SIGHUP 1 가능 가능
SIGUSR1 10 가능 가능
SIGUSR2 12 가능 가능
SIGCHLD 17 가능 가능
SIGTSTP 20 가능 가능
SIGCONT 18 가능 불가능
SIGKILL 9 불가능 불가능
SIGSTOP 19 불가능 불가능

SIGKILL과 SIGSTOP만 가로챌 수 없습니다. 나머지 시그널은 모두 trap으로 처리하거나 무시하도록 설정할 수 있습니다.

시그널 직접 보내보기

# 터미널 1에서: 대기 중인 프로세스 실행cat /dev/urandom | base64 | head -c 10M > /dev/null &echo "PID: $!"# 터미널 2에서: 시그널 보내기kill -STOP 12345    # 일시 정지sleep 2kill -CONT 12345    # 재개sleep 2kill -TERM 12345    # 정상 종료

이처럼 시그널을 직접 보내면서 프로세스 상태 변화를 ps aux로 관찰하면 각 시그널의 동작을 직접 확인할 수 있습니다. STAT 컬럼이 R(실행)에서 T(정지)로 바뀌었다가 다시 R로 돌아오는 것을 볼 수 있습니다.

다음 절에서는 이 시그널들을 스크립트에서 가로채는 방법인 trap을 배웁니다.