我这里并不能完全解释为什么在多线程环境中sigwait()
表现得并不如我所预期。不过,以下是我通过实证得出的一些发现。
首先看这样一个主程序:
from signal import sigwait, SIGALRM, alarm
from time import time
if __name__ == "__main__":
a = time()
alarm(1)
sigwait((SIGALRM,))
b = time()
print(round(b-a, 2))
这个程序运行的结果是:
1.01
这正是我期望的结果——即约1秒的暂停。
接下来考虑这种情况:
from threading import Thread
from signal import sigwait, SIGALRM, alarm
from time import time
class SigTest(Thread):
def __init__(self):
super().__init__()
def run(self):
a = time()
alarm(1)
sigwait((SIGALRM,))
b = time()
print(round(b-a, 2))
if __name__ == "__main__":
t = SigTest()
t.start()
t.join()
当我运行这个代码时,由于alarm信号未被捕获或以其他方式处理,Python执行程序终止。在我的系统上,输出为:
zsh: alarm /usr/local/bin/python3 /Users/CtrlZ/Python/Jan08.py
如果我在run()
方法中添加pthread_sigmask(SIG_BLOCK, (SIGALRM,))
,行为依旧不变——即Python由于SIGALRM未被观察而终止。
进一步探索,我们现在引入一个信号处理器:
from threading import Thread
from signal import signal, sigwait, SIGALRM, SIG_BLOCK, alarm, pthread_sigmask
from time import time
class SigTest(Thread):
def __init__(self):
super().__init__()
signal(SIGALRM, SigTest.handler)
@staticmethod
def handler(signum, _):
print(f"Signal {signum} handled")
def run(self):
mask = (SIGALRM,)
# 注意,即使在这种方式下调用pthread_sigmask(),行为也不会改变
# pthread_sigmask(SIG_BLOCK, mask)
a = time()
alarm(1)
sigwait(mask)
b = time()
print(round(b-a, 2))
if __name__ == "__main__":
t = SigTest()
t.start()
t.join()
这个程序的输出是:
Signal 14 handled
然而,程序随后会无限期地阻塞
综上所述,似乎我对线程中的信号处理机制并未完全理解。
如果有谁能给出这一现象的完整解释,我会非常感激。