Python-Signal Jammer: SIGQUIT Handler verzögert die Ausführung, wenn SIGQUIT während der Ausführung eines anderen Signalhandler empfangen?

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

  •  02-07-2019
  •  | 
  •  

Frage

Das folgende Programm ist sehr einfach: es gibt einen einzigen Punkt jeweils eine halbe Sekunde. Wenn es ein recieves SIGQUIT , geht es zur Ausgabe von zehn F s. Wenn es recieves ein SIGTSTP ( Strg - Z ) , es gibt zehn Z s.

Wenn es ein recieves SIGTSTP beim Drucken F s, wird es zehn drucken Z s, nachdem es mit dem zehn Q getan s. Dies ist eine gute Sache.

Wenn es jedoch recieves ein SIGQUIT beim Drucken Z s, es scheitert drucken Q s nach ihnen. Stattdessen druckt er sich nur, nachdem ich manuell Ausführung über eine KeyboardInterrupt beenden. Ich möchte, dass die F s sofort gedruckt werden, nachdem der Z s.

Dies geschieht python2.3 verwendet wird.

Was mache ich falsch? 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)
War es hilfreich?

Lösung

Ihr größeres Problem wird in Signal-Handler blockiert wird.

Dies ist in der Regel abgeraten, da es zu seltsamen Zeitbedingungen führen kann. Aber es ist nicht ganz die Ursache des Problems, da die Zeitbedingung Sie anfällig sind wegen Ihrer Wahl der Signalhandler vorhanden ist.

Wie auch immer, hier ist, wie zumindest die Zeitbedingung zu minimieren, indem nur Flags in Ihrem Handler Einstellung und Verlassen des Haupt-while-Schleife die eigentliche Arbeit zu tun. Die Erklärung dafür, warum Ihr Code benimmt sich seltsam nach dem Code beschrieben wird.

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

Wie auch immer, hier ist was los ist.

SIGTSTP ist spezieller als SIGQUIT.

SIGTSTP Masken die anderen Signale aus geliefert wird, während seine Signal-Handler ausgeführt wird. Wenn der Kernel SIGQUIT zu liefern geht und sieht, dass SIGTSTP Handler noch läuft, spart es einfach für später. Sobald ein weiteres Signal für die Lieferung kommt durch, wie SIGINT, wenn Sie STRG + C (aka KeyboardInterrupt), der Kern erinnert sich, dass es nie SIGQUIT geliefert und liefert es jetzt.

Sie werden feststellen, wenn Sie while 1: in der Hauptschleife for i in range(60): ändern und Ihren Testfall wieder tun, wird das Programm verlassen, ohne den SIGTSTP Handler läuft seit Ausgang nicht wieder Auslöser des Signallieferungsmechanismus des Kernels.

Viel Glück!

Andere Tipps

Auf Python 2.5.2 auf Linux 2.6.24, Ihr Code funktioniert genau so, wie Sie Ihre gewünschten Ergebnisse beschreiben (wenn ein Signal empfangen wird, während noch eine frühere Signalverarbeitung, wird das neue Signal verarbeitet, unmittelbar nachdem die ersten fertig ist) .

Auf Python 2.4.4 auf Linux 2.6.16, sehe ich das Problem Verhalten, das Sie beschreiben.

Ich weiß nicht, ob dies in Python aufgrund einer Änderung oder im Linux-Kernel.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top