Python信号故障:如果在执行另一个信号处理程序期间收到SIGQUIT,则SIGQUIT处理程序会延迟执行吗?
以下程序非常简单:每半秒钟输出一个点。如果收到SIGQUIT,它将继续输出十个Q。如果接收到SIGTSTP(Ctrl
-Z
),则输出十个Z。
如果在打印Q时收到SIGTSTP,则在完成十个Q后将打印十个Z。这是一件好事。
但是,如果在打印Z时收到SIGQUIT,则无法在其后打印Q。相反,它仅在我通过KeyboardInterrupt手动终止执行后才将它们打印出来。我希望在Z之后立即打印Q。
这是使用Python2.3发生的。
我究竟做错了什么? 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)
解决方案
我们更大的问题是信号处理程序中的阻塞。
通常不建议这样做,因为它可能导致奇怪的计时条件。但这并不是问题的根源,因为由于选择了信号处理程序,因此我们容易受到时序条件的影响。
无论如何,这是通过仅在处理程序中设置标志并保留主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的处理程序仍在运行时,它只是将其保存以备后用。一旦另一个信号通过传递,例如CTRL + C(又名KeyboardInterrupt)时传递给SIGINT,内核就会记住它从未传递过SIGQUIT并立即传递了它。
我们会注意到,如果在主循环中将" while 1:"更改为" for range(60):`中的i"并再次执行测试用例,则程序将退出而不运行SIGTSTP处理程序,因为退出不会重新触发内核的信号传递机制。
祝你好运!
在Linux 2.6.24上的Python 2.5.2上,代码完全按照我们描述的所需结果工作(如果在仍在处理前一个信号的同时接收到信号,则在第一个信号完成后立即处理新信号)。
在Linux 2.6.16上的Python 2.4.4上,我看到了我们描述的问题行为。
我不知道这是由于Python还是Linux内核的变化所致。