Python 신호 문제:다른 신호 처리기 실행 중에 SIGQUIT가 수신되면 SIGQUIT 처리기가 실행을 지연합니까?

StackOverflow https://stackoverflow.com/questions/109705

  •  02-07-2019
  •  | 
  •  

문제

다음 프로그램은 매우 간단합니다.0.5초마다 하나의 점을 출력합니다.수신하는 경우 시그퀴트, 10을 출력합니다. 에스.수신하는 경우 SIGTSTP (Ctrl 키-), 10을 출력합니다 에스.

수신하는 경우 SIGTSTP 인쇄하는 동안 음, 10이 인쇄될 거예요 열 가지 일이 끝난 후야 에스.이것은 좋은 일입니다.

그러나 수신하는 경우 시그퀴트 인쇄하는 동안 아, 인쇄에 실패했어요 그 다음이야.대신, KeyboardInterrupt를 통해 실행을 수동으로 종료한 후에만 인쇄합니다.나는 원한다 s는 바로 다음에 인쇄됩니다. 에스.

이는 Python2.3을 사용하여 발생합니다.

내가 도대체 ​​뭘 잘못하고있는 겁니까?무하스 그라시아스.

#!/usr/bin/python

from signal import *
from time import sleep
from sys import stdout

def write(text):
    stdout.write(text)
    stdout.flush()

def process_quit(signum, frame):
    for i in range(10):
        write("Q")
        sleep(0.5)

def process_tstp(signum, frame):
    for i in range(10):
        write("Z")
        sleep(0.5)

signal(SIGQUIT, process_quit)
signal(SIGTSTP, process_tstp)

while 1:
    write('.')
    sleep(0.5)
도움이 되었습니까?

해결책

더 큰 문제는 신호 처리기에서 차단되는 것입니다.

이는 이상한 타이밍 조건이 발생할 수 있으므로 일반적으로 권장되지 않습니다.그러나 신호 처리기를 선택했기 때문에 취약한 타이밍 조건이 존재하기 때문에 이것이 문제의 원인은 아닙니다.

어쨌든, 처리기에서 플래그만 설정하고 실제 작업을 수행하도록 기본 while 루프를 남겨 두어 최소한 타이밍 조건을 최소화하는 방법은 다음과 같습니다.코드가 이상하게 동작하는 이유에 대한 설명은 코드 뒤에 설명되어 있습니다.

#!/usr/bin/python

from signal import *
from time import sleep
from sys import stdout

print_Qs = 0
print_Zs = 0

def write(text):
    stdout.write(text)
    stdout.flush()

def process_quit(signum, frame):
     global print_Qs
     print_Qs = 10

def process_tstp(signum, frame):
     global print_Zs
     print_Zs = 10

signal(SIGQUIT, process_quit)
signal(SIGTSTP, process_tstp)

while 1:
    if print_Zs:
        print_Zs -= 1
        c = 'Z'
    elif print_Qs:
        print_Qs -= 1
        c = 'Q'
    else:
        c = '.'
    write(c)
    sleep(0.5)

어쨌든, 무슨 일이 일어나고 있는지는 다음과 같습니다.

SIGTSTP는 SIGQUIT보다 더 특별합니다.

SIGTSTP는 신호 처리기가 실행되는 동안 다른 신호가 전달되지 않도록 마스크합니다.커널이 SIGQUIT를 전달하고 SIGTSTP의 핸들러가 아직 실행 중인 것을 확인하면 나중에 사용할 수 있도록 저장해 둡니다.SIGINT와 같은 다른 신호가 전달을 위해 전달되면 CTRL 키+ (일명 KeyboardInterrupt), 커널은 SIGQUIT를 전달한 적이 없다는 것을 기억하고 지금 전달합니다.

변화하면 알게 될 것이다 while 1: 에게 for i in range(60): 메인 루프에서 테스트 사례를 다시 수행하면 종료가 커널의 신호 전달 메커니즘을 다시 트리거하지 않기 때문에 SIGTSTP 핸들러를 실행하지 않고 프로그램이 종료됩니다.

행운을 빌어요!

다른 팁

Linux 2.6.24의 Python 2.5.2에서 코드는 원하는 결과를 설명하는 대로 정확하게 작동합니다(이전 신호를 처리하는 동안 신호가 수신되면 첫 번째 신호가 완료된 후 즉시 새 신호가 처리됩니다).

Linux 2.6.16의 Python 2.4.4에서 설명하는 문제 동작을 볼 수 있습니다.

이것이 Python의 변경 때문인지 Linux 커널의 변경 때문인지는 알 수 없습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top