"signal" --- Set handlers for asynchronous events
*************************************************

**소스 코드:** Lib/signal.py

======================================================================

이 모듈은 파이썬에서 시그널 처리기를 사용하는 메커니즘을 제공합니다.


일반 규칙
=========

"signal.signal()" 함수는 시그널이 수신될 때 실행될 사용자 정의 처리기
를 정의하도록 합니다. 소수의 기본 처리기가 설치됩니다: "SIGPIPE"는 무
시되고 (그래서 파이프와 소켓에 대한 쓰기 에러는 일반 파이썬 예외로 보
고될 수 있습니다) "SIGINT"는 부모 프로세스가 변경하지 않았다면
"KeyboardInterrupt" 예외로 번역됩니다.

일단 설정되면, 특정 시그널에 대한 처리기는 명시적으로 재설정 될 때까지
(파이썬은 하부 구현과 관계없이 BSD 스타일 인터페이스를 흉내 냅니다) 설
치된 상태로 유지됩니다. "SIGCHLD"에 대한 처리기는 예외인데, 하부 구현
을 따릅니다.


파이썬 시그널 처리기의 실행
---------------------------

파이썬 시그널 처리기는 저수준 (C) 시그널 처리기 내에서 실행되지 않습니
다. 대신, 저수준 시그널 처리기는 *가상 기계*에게 나중에 (예를 들어 다
음 *바이트 코드* 명령에서) 해당 파이썬 시그널 처리기를 실행하도록 지시
하는 플래그를 설정합니다. 결과는 다음과 같습니다:

* C 코드에서의 유효하지 않은 연산으로 인해 발생하는 "SIGFPE"나
  "SIGSEGV"와 같은 동기 에러를 잡는 것은 그리 의미가 없습니다. 파이썬
  은 시그널 처리기에서 C 코드로 돌아오는데, 같은 시그널을 다시 발생시
  켜서, 파이썬이 멈출 것입니다. 파이썬 3.3부터는, "faulthandler" 모듈
  을 사용하여 동기 에러를 보고할 수 있습니다.

* C로만 구현된 오래 실행되는 계산(가령 커다란 텍스트 본문에 대한 정규
  식 일치)은 수신된 시그널에 상관없이 임의의 시간 동안 중단없이 실행될
  수 있습니다. 계산이 끝나면 파이썬 시그널 처리기가 호출됩니다.

* If the handler raises an exception, it will be raised "out of thin
  air" in the main thread. See the note below for a discussion.


시그널과 스레드
---------------

파이썬 시그널 처리기는 시그널이 다른 스레드에서 수신될 때도 항상 메인
인터프리터의 메인 파이썬 스레드에서 실행됩니다. 이는 시그널을 스레드
간 통신 수단으로 사용할 수 없음을 의미합니다. 대신 "threading" 모듈의
동기화 프리미티브를 사용할 수 있습니다.

게다가, 메인 인터프리터의 메인 스레드만 새로운 시그널 처리기를 설정할
수 있습니다.


모듈 내용
=========

버전 3.5에서 변경: signal (SIG*), handler ("SIG_DFL", "SIG_IGN") and
sigmask ("SIG_BLOCK", "SIG_UNBLOCK", "SIG_SETMASK") related constants
listed below were turned into "enums". "getsignal()",
"pthread_sigmask()", "sigpending()" and "sigwait()" functions return
human-readable "enums".

"signal" 모듈에 정의된 변수는 다음과 같습니다:

signal.SIG_DFL

   이것은 두 가지 표준 시그널 처리 옵션 중 하나입니다; 단순히 시그널의
   기본 기능을 수행합니다. 예를 들어, 대부분의 시스템에서 "SIGQUIT"의
   기본 동작은 코어를 덤프하고 종료하는 것이지만, "SIGCHLD"의 기본 동
   작은 단순히 무시하는 것입니다.

signal.SIG_IGN

   이것은 주어진 시그널을 무시하는 또 다른 표준 시그널 처리기입니다.

signal.SIGABRT

   *abort(3)*로 부터의 중단 시그널.

signal.SIGALRM

   *alarm(2)*로 부터의 타이머 시그널.

   Availability: Unix.

signal.SIGBREAK

   키보드 인터럽트 (CTRL + BREAK).

   Availability: Windows.

signal.SIGBUS

   버스 에러 (메모리 액세스 불량).

   Availability: Unix.

signal.SIGCHLD

   자식 프로세스가 중지되었거나 종료되었습니다.

   Availability: Unix.

signal.SIGCLD

   "SIGCHLD"에 대한 별칭.

signal.SIGCONT

   현재 중지되었으면 프로세스를 재개합니다.

   Availability: Unix.

signal.SIGFPE

   부동 소수점 예외. 예를 들어, 0으로 나누기.

   더 보기: 나누기나 모듈로 연산의 두 번째 인자가 0이면 "ZeroDivisionError"가
         발생합니다.

signal.SIGHUP

   제어 터미널이 끊어졌거나 제어 프로세스가 죽었습니다.

   Availability: Unix.

signal.SIGILL

   잘못된 명령어.

signal.SIGINT

   키보드 인터럽트 (CTRL + C).

   기본 액션은 "KeyboardInterrupt"를 발생시키는 것입니다.

signal.SIGKILL

   킬 시그널.

   잡거나, 차단하거나, 무시할 수 없습니다.

   Availability: Unix.

signal.SIGPIPE

   끊어진 파이프: 판독기가 없는 파이프에 쓰기.

   기본 동작은 시그널을 무시하는 것입니다.

   Availability: Unix.

signal.SIGSEGV

   세그먼테이션 오류: 유효하지 않은 메모리 참조.

signal.SIGTERM

   종료 시그널.

signal.SIGUSR1

   사용자 정의 시그널 1.

   Availability: Unix.

signal.SIGUSR2

   사용자 정의 시그널 2.

   Availability: Unix.

signal.SIGWINCH

   창 크기 조정 시그널.

   Availability: Unix.

SIG*

   모든 시그널 번호는 기호적으로 정의됩니다. 예를 들어, 행업(hangup)
   시그널은 "signal.SIGHUP"으로 정의됩니다; 변수 이름은 "<signal.h>"에
   있는 C 프로그램에서 사용되는 이름과 동일합니다. '"signal()"'에 대한
   유닉스 매뉴얼 페이지는 존재하는 시그널을 나열합니다 (일부 시스템에
   서는 *signal(2)*이고, 다른 시스템에서는 *signal(7)*입니다). 모든 시
   스템이 같은 시그널 이름 집합을 정의하는 것은 아님에 유의하십시오;
   시스템에서 정의한 이름만 이 모듈에서 정의합니다.

signal.CTRL_C_EVENT

   "Ctrl+C" 키 입력 이벤트에 해당하는 시그널. 이 시그널은 "os.kill()"
   에서만 사용할 수 있습니다.

   Availability: Windows.

   버전 3.2에 추가.

signal.CTRL_BREAK_EVENT

   "Ctrl+Break" 키 입력 이벤트에 해당하는 시그널. 이 시그널은
   "os.kill()"에서만 사용할 수 있습니다.

   Availability: Windows.

   버전 3.2에 추가.

signal.NSIG

   One more than the number of the highest signal number.

signal.ITIMER_REAL

   간격 타이머(interval timer)를 실시간으로 감소시키고, 만료 시
   "SIGALRM"을 전달합니다.

signal.ITIMER_VIRTUAL

   프로세스가 실행 중일 때만 간격 타이머(interval timer)를 감소시키고,
   만료 시 SIGVTALRM을 전달합니다.

signal.ITIMER_PROF

   프로세스가 실행될 때와 시스템이 프로세스를 대신하여 실행될 때 간격
   타이머(interval timer)를 감소시킵니다. ITIMER_VIRTUAL과 함께 사용되
   어, 이 타이머는 일반적으로 사용자와 커널 공간에서 응용 프로그램이
   소비한 시간을 프로파일링하는 데 사용됩니다. 만료 시 SIGPROF를 전달
   합니다.

signal.SIG_BLOCK

   "pthread_sigmask()"의 *how* 매개 변수에 가능한 값으로 시그널이 차단
   됨을 나타냅니다.

   버전 3.3에 추가.

signal.SIG_UNBLOCK

   "pthread_sigmask()"의 *how* 매개 변수에 가능한 값으로 시그널이 차단
   해제됨을 나타냅니다.

   버전 3.3에 추가.

signal.SIG_SETMASK

   "pthread_sigmask()"의 *how* 매개 변수에 가능한 값으로 시그널 마스크
   가 교체됨을 나타냅니다.

   버전 3.3에 추가.

"signal" 모듈은 하나의 예외를 정의합니다:

exception signal.ItimerError

   하부 "setitimer()"나 "getitimer()" 구현으로부터의 에러를 알리기 위
   해 발생합니다. 유효하지 않은 간격 타이머나 음의 시간이
   "setitimer()"에 전달되면 이 에러가 예상됩니다. 이 에러는 "OSError"
   의 서브 형입니다.

   버전 3.3에 추가: 이 에러는 "IOError"의 서브 형이었습니다, 이제는
   "OSError"의 별칭입니다.

"signal" 모듈은 다음 함수를 정의합니다:

signal.alarm(time)

   *time*이 0이 아니면, 이 함수는 "SIGALRM" 시그널이 *time* 초 내에 프
   로세스로 전송되도록 요청합니다. 이전에 예약된 알람은 취소됩니다 (임
   의의 시간에 오직 하나의 알람만 예약될 수 있습니다). 반환된 값은 이
   전에 설정된 알람이 전달되기까지 남은 초(seconds)입니다. *time*이 0
   이면, 알람이 예약되지 않고, 예약된 알람이 취소됩니다. 반환 값이 0이
   면, 현재 예약된 알람이 없습니다.

   Availability: Unix.  See the man page *alarm(2)* for further
   information.

signal.getsignal(signalnum)

   시그널 *signalnum*에 대한 현재 시그널 처리기를 반환합니다. 반환된
   값은 콜러블 파이썬 객체이거나, 특수 값 "signal.SIG_IGN",
   "signal.SIG_DFL" 중 하나이거나 "None"일 수 있습니다. 여기서
   "signal.SIG_IGN"은 시그널이 이전에 무시되었음을 의미하고,
   "signal.SIG_DFL"은 시그널을 처리하는 기본 방법이 이전에 사용 중임을
   의미하고, "None"은 이전 시그널 처리기가 파이썬에서 설치되지 않았음
   을 의미합니다.

signal.strsignal(signalnum)

   Return the system description of the signal *signalnum*, such as
   "Interrupt", "Segmentation fault", etc. Returns "None" if the
   signal is not recognized.

   버전 3.8에 추가.

signal.valid_signals()

   이 플랫폼에서 유효한 시그널 번호 집합을 반환합니다. 일부 시그널이
   시스템에서 내부 용으로 예약되었으면 "range(1, NSIG)"보다 작을 수 있
   습니다.

   버전 3.8에 추가.

signal.pause()

   시그널이 수신될 때까지 프로세스를 휴면 상태로 만듭니다; 그런 다음
   적절한 처리기가 호출됩니다. 아무것도 반환하지 않습니다.

   Availability: Unix.  See the man page *signal(2)* for further
   information.

   "sigwait()", "sigwaitinfo()", "sigtimedwait()" 및 "sigpending()"도
   참조하십시오.

signal.raise_signal(signum)

   호출하는 프로세스에 시그널을 보냅니다. 아무것도 반환하지 않습니다.

   버전 3.8에 추가.

signal.pidfd_send_signal(pidfd, sig, siginfo=None, flags=0)

   파일 기술자 *pidfd*가 참조하는 프로세스로 시그널 *sig*를 보냅니다.
   파이썬은 현재 *siginfo* 매개 변수를 지원하지 않습니다; "None"이어야
   합니다. *flags* 인자는 향후 확장을 위해 제공됩니다; 현재는 플래그
   값이 정의되어 있지 않습니다.

   자세한 내용은 *pidfd_send_signal(2)* 매뉴얼 페이지를 참조하십시오.

   Availability: Linux 5.1+

   버전 3.9에 추가.

signal.pthread_kill(thread_id, signalnum)

   시그널 *signalnum*을 호출자와 같은 프로세스의 다른 스레드인 스레드
   *thread_id*로 보냅니다. 대상 스레드는 임의의 (파이썬이거나 아닌) 코
   드를 실행 중일 수 있습니다. 그러나, 대상 스레드가 파이썬 인터프리터
   를 실행 중이면, 파이썬 시그널 처리기는 메인 인터프리터의 메인 스레
   드에서 실행됩니다. 따라서, 특정 파이썬 스레드에 시그널을 보내는 것
   의 유일한 용도는 실행 중인 시스템 호출이 "InterruptedError"로 실패
   하도록 하는 것입니다.

   Use "threading.get_ident()" or the "ident" attribute of
   "threading.Thread" objects to get a suitable value for *thread_id*.

   *signalnum*이 0이면, 시그널이 전송되지 않지만, 여전히 에러 검사가
   수행됩니다; 대상 스레드가 여전히 실행 중인지 확인하는 데 사용할 수
   있습니다.

   인자 "thread_id", "signalnum"으로 감사 이벤트 "signal.pthread_kill"
   을 발생시킵니다.

   Availability: Unix.  See the man page *pthread_kill(3)* for further
   information.

   "os.kill()"도 참조하십시오.

   버전 3.3에 추가.

signal.pthread_sigmask(how, mask)

   호출하는 스레드의 시그널 마스크를 가져오거나 변경하거나 가져오면서
   변경합니다. 시그널 마스크는 호출자에게 현재 배달이 차단된 시그널 집
   합입니다. 이전 시그널 마스크를 시그널 집합으로 반환합니다.

   호출의 동작은 다음과 같이 *how* 값에 따라 다릅니다.

   * "SIG_BLOCK": 차단된 시그널 집합은 현재 집합과 *mask* 인자의 합집
     합입니다.

   * "SIG_UNBLOCK": *mask*에 있는 시그널이 차단된 시그널의 현재 집합에
     서 제거됩니다. 차단되지 않은 시그널을 차단 해제하려고 시도할 수
     있습니다.

   * "SIG_SETMASK": 차단된 시그널 집합이 *mask* 인자로 설정됩니다.

   *mask*는 시그널 번호 집합입니다 (예를 들어 {"signal.SIGINT",
   "signal.SIGTERM"}). 모든 시그널을 포함한 전체 마스크를 얻으려면
   "valid_signals()"를 사용하십시오.

   예를 들어, "signal.pthread_sigmask(signal.SIG_BLOCK, [])"은 호출하
   는 스레드의 시그널 마스크를 읽습니다.

   "SIGKILL"과 "SIGSTOP"은 차단할 수 없습니다.

   Availability: Unix.  See the man page *sigprocmask(2)* and
   *pthread_sigmask(3)* for further information.

   "pause()", "sigpending()" 및 "sigwait()"도 참조하십시오.

   버전 3.3에 추가.

signal.setitimer(which, seconds, interval=0.0)

   *seconds*("alarm()"과 달리 float가 허용됩니다) 이후에 그리고
   (*interval*이 0이 아니면) 그 후로 *interval* 초마다 발사(fire)하도
   록 *which*로 지정된 간격 타이머("signal.ITIMER_REAL",
   "signal.ITIMER_VIRTUAL" 또는 "signal.ITIMER_PROF" 중 하나)를 설정합
   니다. *which*로 지정된 간격 타이머는 *seconds*를 0으로 설정하여 지
   울 수 있습니다.

   간격 타이머가 발사(fire)하면, 시그널이 프로세스로 전송됩니다. 전송
   된 시그널은 사용 중인 타이머에 따라 다릅니다; "signal.ITIMER_REAL"
   은 "SIGALRM"을, "signal.ITIMER_VIRTUAL"은 "SIGVTALRM"을,
   "signal.ITIMER_PROF"는 "SIGPROF"를 전달합니다.

   이전 값은 튜플로 반환됩니다: (지연, 간격).

   유효하지 않은 간격 타이머를 전달하려고 하면 "ItimerError"가 발생합
   니다.

   Availability: Unix.

signal.getitimer(which)

   *which*로 지정된 주어진 간격 타이머의 현재 값을 반환합니다.

   Availability: Unix.

signal.set_wakeup_fd(fd, *, warn_on_full_buffer=True)

   Set the wakeup file descriptor to *fd*.  When a signal is received,
   the signal number is written as a single byte into the fd.  This
   can be used by a library to wakeup a poll or select call, allowing
   the signal to be fully processed.

   이전 웨이크업 fd가 반환됩니다 (또는 파일 기술자 웨이크업이 활성화되
   지 않았으면 -1). *fd*가 -1이면, 파일 기술자 웨이크업이 비활성화됩니
   다. -1이 아니면, *fd*는 비 블로킹이어야 합니다. poll이나 select를
   다시 호출하기 전에 *fd*에서 바이트를 제거하는 것은 라이브러리의 책
   임입니다.

   스레드가 활성화되었을 때, 이 함수는 메인 인터프리터의 메인 스레드에
   서만 호출할 수 있습니다; 다른 스레드에서 호출하려고 하면
   "ValueError" 예외가 발생합니다.

   이 함수를 사용하는 일반적인 두 가지 방법이 있습니다. 두 방법 모두,
   시그널이 도착할 때 깨어나기 위해 fd를 사용하지만, *어떤* 시그널이나
   시그널들이 도착했는지 판단하는 방법이 다릅니다.

   첫 번째 방법에서는, fd의 버퍼에서 데이터를 읽고, 바이트 값이 시그널
   번호를 제공합니다. 이것은 간단합니다만, 드물게 문제가 될 수 있습니
   다: 일반적으로 fd에는 제한된 버퍼 공간이 있으며, 너무 많은 시그널이
   너무 빨리 도착하면, 버퍼가 가득 차고, 일부 시그널이 손실될 수 있습
   니다. 이 방법을 사용하면, 시그널이 손실될 때 최소한 stderr에 경고가
   인쇄되도록 "warn_on_full_buffer=True"를 설정해야 합니다.

   두 번째 방법에서는, 오직 웨이크업만을 위해 웨이크업 fd를 사용하고,
   실제 바이트 값은 무시합니다. 이 경우, 우리가 신경 쓰는 것은 fd의 버
   퍼가 비어 있는지 비어 있지 않은지 입니다; 가득 찬 버퍼는 전혀 문제
   를 가리키지 않습니다. 이 방법을 사용하면, 사용자가 가짜 경고 메시지
   로 혼동되지 않도록 "warn_on_full_buffer=False"를 설정해야 합니다.

   버전 3.5에서 변경: 윈도우에서, 이 함수는 이제 소켓 핸들도 지원합니
   다.

   버전 3.7에서 변경: "warn_on_full_buffer" 매개 변수를 추가했습니다.

signal.siginterrupt(signalnum, flag)

   시스템 호출 재시작 동작을 변경합니다: *flag*가 "False"이면, 시그널
   *signalnum*에 의해 인터럽트 될 때 시스템 호출이 다시 시작되고, 그렇
   지 않으면 시스템 호출이 중단됩니다. 아무것도 반환하지 않습니다.

   Availability: Unix.  See the man page *siginterrupt(3)* for further
   information.

   Note that installing a signal handler with "signal()" will reset
   the restart behaviour to interruptible by implicitly calling
   "siginterrupt()" with a true *flag* value for the given signal.

signal.signal(signalnum, handler)

   시그널 *signalnum*의 처리기를 함수 *handler*로 설정합니다.
   *handler*는 두 개의 인자(아래를 참조하십시오)를  취하는 콜러블 파이
   썬 객체, 또는 특수 값 "signal.SIG_IGN"이나 "signal.SIG_DFL" 중 하나
   일 수 있습니다. 이전 시그널 처리기가 반환됩니다 (위의 "getsignal()"
   설명을 참조하십시오). (자세한 내용은 유닉스 매뉴얼 페이지
   *signal(2)*를 참조하십시오.)

   스레드가 활성화되었을 때, 이 함수는 메인 인터프리터의 메인 스레드에
   서만 호출할 수 있습니다; 다른 스레드에서 호출하려고 하면
   "ValueError" 예외가 발생합니다.

   *handler*는 두 개의 인자로 호출됩니다: 시그널 번호와 현재 스택 프레
   임 ("None"이나 프레임 객체; 프레임 객체에 대한 설명은, 형 계층에 있
   는 설명을 참조하거나 "inspect" 모듈의 어트리뷰트 설명을 참조하십시
   오).

   윈도우에서, "signal()"은 "SIGABRT", "SIGFPE", "SIGILL", "SIGINT",
   "SIGSEGV", "SIGTERM" 또는 "SIGBREAK"로만 호출 할 수 있습니다. 다른
   경우에는 "ValueError"가 발생합니다. 모든 시스템이 같은 시그널 이름
   집합을 정의하는 것은 아님에 유의하십시오; 시그널 이름이 "SIG*" 모듈
   수준 상수로 정의되지 않으면 "AttributeError"가 발생합니다.

signal.sigpending()

   호출하는 스레드로 전달 계류 중인 시그널 집합을 검사합니다 (즉, 차단
   된 동안 발생한 시그널). 계류 중인 시그널 집합을 반환합니다.

   Availability: Unix.  See the man page *sigpending(2)* for further
   information.

   "pause()", "pthread_sigmask()" 및 "sigwait()"도 참조하십시오.

   버전 3.3에 추가.

signal.sigwait(sigset)

   시그널 집합 *sigset*에 지정된 시그널 중 하나가 전달될 때까지 호출하
   는 스레드의 실행을 일시 중단합니다. 이 함수는 시그널을 받아들이고 (
   계류 중인 시그널 목록에서 제거합니다), 시그널 번호를 반환합니다.

   Availability: Unix.  See the man page *sigwait(3)* for further
   information.

   "pause()", "pthread_sigmask()", "sigpending()", "sigwaitinfo()" 및
   "sigtimedwait()"도 참조하십시오.

   버전 3.3에 추가.

signal.sigwaitinfo(sigset)

   시그널 집합 *sigset*에 지정된 시그널 중 하나가 전달될 때까지 호출하
   는 스레드의 실행을 일시 중단합니다. 이 함수는 시그널을 받아들이고
   계류 중인 시그널 목록에서 제거합니다. *sigset*의 시그널 중 하나가
   이미 호출하는 스레드에 대해 계류 중이면, 함수는 해당 시그널에 대한
   정보와 함께 즉시 반환합니다. 전달된 시그널에 대해 시그널 처리기가
   호출되지 않습니다. 이 함수는 *sigset*에 없는 시그널에 의해 중단되면
   "InterruptedError"를 발생시킵니다.

   반환 값은 "siginfo_t" 구조체에 포함된 데이터, 즉 "si_signo",
   "si_code", "si_errno", "si_pid", "si_uid", "si_status", "si_band"를
   표현하는 객체입니다.

   Availability: Unix.  See the man page *sigwaitinfo(2)* for further
   information.

   "pause()", "sigwait()" 및 "sigtimedwait()"도 참조하십시오.

   버전 3.3에 추가.

   버전 3.5에서 변경: 이 함수는 이제 *sigset*에 없는 시그널에 의해 중
   단되고 시그널 처리기가 예외를 발생시키지 않으면 재시도됩니다 (이유
   는 **PEP 475**를 참조하십시오).

signal.sigtimedwait(sigset, timeout)

   Like "sigwaitinfo()", but takes an additional *timeout* argument
   specifying a timeout. If *timeout* is specified as "0", a poll is
   performed. Returns "None" if a timeout occurs.

   Availability: Unix.  See the man page *sigtimedwait(2)* for further
   information.

   "pause()", "sigwait()" 및 "sigwaitinfo()"도 참조하십시오.

   버전 3.3에 추가.

   버전 3.5에서 변경: 이 함수는 이제 *sigset*에 없는 시그널에 의해 중
   단되고 시그널 처리기가 예외를 발생시키지 않으면 다시 계산된
   *timeout*으로 재시도됩니다 (이유는 **PEP 475**를 참조하십시오).


Example
=======

다음은 최소한의 예제 프로그램입니다. "alarm()" 함수를 사용하여 파일을
여는 데 대기하는 시간을 제한합니다; 이것은 파일이 켜져 있지 않을 수 있
는 직렬 장치를 위한 파일일 때 유용하며, 일반적으로 "os.open()"이 무기
한 정지됩니다. 해결책은 파일을 열기 전에 5초 알람을 설정하는 것입니다;
작업이 너무 오래 걸리면, 알람 시그널이 전송되고, 처리기가 예외를 발생
시킵니다.

   import signal, os

   def handler(signum, frame):
       print('Signal handler called with signal', signum)
       raise OSError("Couldn't open device!")

   # Set the signal handler and a 5-second alarm
   signal.signal(signal.SIGALRM, handler)
   signal.alarm(5)

   # This open() may hang indefinitely
   fd = os.open('/dev/ttyS0', os.O_RDWR)

   signal.alarm(0)          # Disable the alarm


SIGPIPE에 대한 참고 사항
========================

프로그램의 출력을 *head(1)*와 같은 도구로 파이핑 하면 표준 출력의 수신
기가 일찍 닫힐 때 여러분의 프로세스로 "SIGPIPE" 시그널이 전송됩니다.
이것은 "BrokenPipeError: [Errno 32] Broken pipe"와 같은 예외를 일으킵
니다. 이 경우를 처리하려면, 다음과 같이 이 예외를 포착하도록 진입점을
감싸십시오:

   import os
   import sys

   def main():
       try:
           # simulate large output (your code replaces this loop)
           for x in range(10000):
               print("y")
           # flush output here to force SIGPIPE to be triggered
           # while inside this try block.
           sys.stdout.flush()
       except BrokenPipeError:
           # Python flushes standard streams on exit; redirect remaining output
           # to devnull to avoid another BrokenPipeError at shutdown
           devnull = os.open(os.devnull, os.O_WRONLY)
           os.dup2(devnull, sys.stdout.fileno())
           sys.exit(1)  # Python exits with error code 1 on EPIPE

   if __name__ == '__main__':
       main()

"BrokenPipeError"를 피하고자 "SIGPIPE"의 배치를 "SIG_DFL"로 설정하지
마십시오. 그렇게 하면 프로그램이 여전히 쓰고 있는 동안 소켓 연결이 중
단될 때마다 프로그램이 예기치 않게 종료되도록 합니다.


신호 처리기와 예외에 대한 참고 사항
===================================

If a signal handler raises an exception, the exception will be
propagated to the main thread and may be raised after any *bytecode*
instruction. Most notably, a "KeyboardInterrupt" may appear at any
point during execution. Most Python code, including the standard
library, cannot be made robust against this, and so a
"KeyboardInterrupt" (or any other exception resulting from a signal
handler) may on rare occasions put the program in an unexpected state.

To illustrate this issue, consider the following code:

   class SpamContext:
       def __init__(self):
           self.lock = threading.Lock()

       def __enter__(self):
           # If KeyboardInterrupt occurs here, everything is fine
           self.lock.acquire()
           # If KeyboardInterrupt occurs here, __exit__ will not be called
           ...
           # KeyboardInterrupt could occur just before the function returns

       def __exit__(self, exc_type, exc_val, exc_tb):
           ...
           self.lock.release()

For many programs, especially those that merely want to exit on
"KeyboardInterrupt", this is not a problem, but applications that are
complex or require high reliability should avoid raising exceptions
from signal handlers. They should also avoid catching
"KeyboardInterrupt" as a means of gracefully shutting down.  Instead,
they should install their own "SIGINT" handler. Below is an example of
an HTTP server that avoids "KeyboardInterrupt":

   import signal
   import socket
   from selectors import DefaultSelector, EVENT_READ
   from http.server import HTTPServer, SimpleHTTPRequestHandler

   interrupt_read, interrupt_write = socket.socketpair()

   def handler(signum, frame):
       print('Signal handler called with signal', signum)
       interrupt_write.send(b'\0')
   signal.signal(signal.SIGINT, handler)

   def serve_forever(httpd):
       sel = DefaultSelector()
       sel.register(interrupt_read, EVENT_READ)
       sel.register(httpd, EVENT_READ)

       while True:
           for key, _ in sel.select():
               if key.fileobj == interrupt_read:
                   interrupt_read.recv(1)
                   return
               if key.fileobj == httpd:
                   httpd.handle_request()

   print("Serving on port 8000")
   httpd = HTTPServer(('', 8000), SimpleHTTPRequestHandler)
   serve_forever(httpd)
   print("Shutdown...")
