Python problemas de sinal: SIGQUIT atrasos manipulador de execução se SIGQUIT recebeu durante a execução de outro manipulador de sinal?

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

  •  02-07-2019
  •  | 
  •  

Pergunta

O programa a seguir é muito simples: ele produz um único ponto cada meio segundo. Se ele recebe um SIGQUIT , procede-se a dez saída Q s. Se ele recebe um SIGTSTP ( Ctrl - Z ) , ele produz dez Z s.

Se ele recebe um SIGTSTP durante a impressão Q é, ele irá imprimir dez Z é depois que é feito com os dez Q s. Isso é uma coisa boa.

No entanto, se ele recebe um SIGQUIT durante a impressão Z é, ele não consegue imprimir Q é depois deles. Em vez disso, ele imprime-los somente depois que eu terminar manualmente a execução através de um KeyboardInterrupt. Eu quero que o Q é a ser impresso imediatamente após o Z s.

Isso acontece usando python2.3.

O que estou fazendo de errado? Muchas gracias.

#!/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)
Foi útil?

Solução

Seu maior problema é o bloqueio em manipuladores de sinal.

Isso geralmente é desencorajado, uma vez que pode levar a condições de tempo estranhos. Mas não é exatamente a causa do seu problema uma vez que a condição de tempo que você está vulnerável a existe por causa de sua escolha de manipuladores de sinais.

De qualquer forma, aqui está como, pelo menos, minimizar a condição de tempo, definindo única bandeiras em seus manipuladores e deixando o principal loop while para fazer o trabalho real. A explicação para por que seu código está se comportando estranhamente é descrito após o código.

#!/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)

De qualquer forma, aqui está o que está acontecendo.

SIGTSTP é mais especial do que SIGQUIT.

máscaras SIGTSTP os outros sinais de ser entregue, enquanto o seu manipulador de sinal está sendo executado. Quando o kernel vai entregar SIGQUIT e vê que manipulador de SIGTSTP ainda está em execução, ele simplesmente salva-lo para mais tarde. Uma vez que um outro sinal vem através de entrega, como SIGINT quando você Ctrl + C (aka KeyboardInterrupt), o kernel lembra que nunca entregues SIGQUIT e entrega-lo agora.

Você vai notar se você mudar while 1: para for i in range(60): no circuito principal e fazer o seu caso de teste novamente, o programa vai sair sem executar o manipulador SIGTSTP desde a saída não re-trigger mecanismo de entrega de sinal do kernel.

Boa sorte!

Outras dicas

Em Python 2.5.2 no Linux 2.6.24, o código funciona exatamente como você descreve os resultados desejados (se um sinal é recebido enquanto ainda processamento de um sinal anterior, o novo sinal é processado imediatamente após o primeiro é terminado) .

Em Python 2.4.4 no Linux 2.6.16, eu ver o comportamento problema que você descreve.

Eu não sei se isso é devido a uma mudança no Python ou no kernel do Linux.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top