Следующая программа очень проста: она выводит одну точку каждые полсекунды. Если он получает SIGQUIT, он переходит к выводу десяти Q. Если он получает SIGTSTP(Ctrl-Z), он выводит десять Z.
Если он получает SIGTSTP во время печати Q, он напечатает десять Z после того, как это будет сделано с десятью Q. Это хорошая вещь.
Однако, если он получает SIGQUIT во время печати Z, он не может печатать Q после них. Вместо этого он распечатывает их только после того, как я вручную завершу выполнение с помощью KeyboardInterrupt. Я хочу, чтобы Q печатались сразу после Z.
Это происходит с использованием 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 + C (также известный как KeyboardInterrupt), ядро запоминает, что оно никогда не доставляло SIGQUIT, и доставляет его сейчас.
Вы заметите, что если вы измените while 1: на for i in range(60): в основном цикле и снова выполните свой тестовый пример, программа завершится без запуска обработчика SIGTSTP, поскольку exit не запускает повторно механизм доставки сигнала ядра.
Удачи!
В Python 2.5.2 в Linux 2.6.24 ваш код работает точно так, как вы описываете желаемые результаты (если сигнал получен при обработке предыдущего сигнала, новый сигнал обрабатывается сразу после завершения первого).
В Python 2.4.4 в Linux 2.6.16 я вижу описанное вами проблемное поведение.
Я не знаю, связано ли это с изменением Python или ядра Linux.