Python信号问题:如果在执行另一个信号处理程序时收到SIGQUIT,SIGQUIT处理程序会延迟执行吗?
下面这个程序非常简单:它每半秒输出一个点。如果接收到一个SIGQUIT信号,它会输出十个Q。如果接收到一个SIGTSTP信号(也就是按下Ctrl-Z),它会输出十个Z。
如果在打印Q的时候接收到SIGTSTP信号,它会在完成十个Q的输出后再打印十个Z。这其实是个好事。
但是,如果在打印Z的时候接收到SIGQUIT信号,它就不会在打印完Z后立即打印Q。相反,只有在我手动终止程序(通过键盘中断)后,它才会打印出Q。我希望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)
2 个回答
在Linux 2.6.24上使用Python 2.5.2时,你的代码的运行结果正好和你想要的一样(如果在处理一个信号的时候又收到了另一个信号,新信号会在第一个信号处理完后立即处理)。
而在Linux 2.6.16上使用Python 2.4.4时,我看到了你所描述的问题表现。
我不确定这是否是因为Python或Linux内核的某些变化导致的。
你遇到的更大问题是信号处理器中的阻塞。
通常来说,这种做法是不推荐的,因为它可能导致一些奇怪的时间条件。不过,这并不是你问题的根本原因,因为你所面临的时间问题是由于你选择的信号处理器造成的。
无论如何,这里有一种方法可以至少减少这种时间问题,那就是在你的处理器中只设置标志,而把实际的工作留给主循环来完成。关于你的代码为什么表现得奇怪的解释在代码之后。
#!/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的处理器还在运行,它就会把SIGQUIT信号暂时保存起来。等到另一个信号到来,比如你按下CTRL+C(也叫KeyboardInterrupt)时,内核会记得之前没有发送的SIGQUIT信号,并在这时发送它。
你会注意到,如果你把主循环中的while 1:
改成for i in range(60):
,然后再测试一次,程序会在不运行SIGTSTP处理器的情况下退出,因为退出不会重新触发内核的信号传递机制。
祝你好运!