Ваша большая проблема - блокировка в обработчиках сигналов.
Обычно это не рекомендуется, поскольку это может привести к странным временным условиям. Но это не совсем причина вашей проблемы, так как существует условие синхронизации, к которому вы уязвимы из-за вашего выбора обработчиков сигналов.
В любом случае, вот как, по крайней мере, минимизировать условие синхронизации, устанавливая только флаги в ваших обработчиках и оставляя основной цикл 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 + C (он же KeyboardInterrupt), ядро запоминает, что оно никогда не доставляло SIGQUIT, и доставляет его сейчас.
Вы заметите, что если вы измените while 1:
на for i in range(60):
в главном цикле и повторите тест, программа выйдет без запуска обработчика SIGTSTP, так как выход не запускает механизм доставки сигналов ядра.
Удачи!