10.2.6 信号和线程
信号和线程通常不能很好地合作,因为只有进程的主线程可以接收信号。下面的例子建立了一个信号处理器,它在一个线程中等待信号,而从另一个线程发送信号。
import signal
import threading
import os
import time
def signal_handler(num,stack):
print('Received signal {} in {}'.format(
num,threading.currentThread().name))
signal.signal(signal.SIGUSR1,signal_handler)
def wait_for_signal():
print('Waiting for signal in',
threading.currentThread().name)
signal.pause()
print('Done waiting')
# start a thread that will not receive the signal.
receiver = threading.Thread(
target=wait_for_signal,
name='receiver',
)
receiver.start()
time.sleep(0.1)
def send_signal():
print('Sending signal in',threading.currentThread().name)
os.kill(os.getpid(),signal.SIGUSR1)
sender = threading.Thread(target=send_signal,name='sender')
sender.start()
sender.join()
# Wait for the thread to see the signal (not going to happen!).
print('Waiting for',receiver.name)
signal.alarm(2)
receiver.join()
信号处理器都在主线程中注册,因为这是Python的signal模块实现的一个要求,不论底层平台如何支持线程和信号的结合,都有这个要求。尽管接收者线程调用了signal.pause()但它不会接收信号。这个例子快要结束时的signal.alarm(2)调用避免了无限阻塞,因为接收者线程永远不会退出。
运行结果:
尽管在任何线程中都能设置闹铃,但其总是由主线程接收。
import signal
import time
import threading
def signal_handler(num,stack):
print(time.ctime(),'Alarm in',
threading.currentThread().name)
signal.signal(signal.SIGALRM,signal_handler)
def use_alarm():
t_name = threading.currentThread().name
print(time.ctime(),'Setting alarm in',t_name)
signal.alarm(1)
print(time.ctime(),'Sleeping in',t_name)
time.sleep(3)
print(time.ctime(),'Done with sleep in',t_name)
# Start a thread that will not receive the signal.
alarm_thread = threading.Thread(
target=use_alarm,
name='alarm_thread',
)
alarm_thread.start()
time.sleep(0.1)
# Wait for the thread to see the signal (not going to happen!).
print(time.ctime(),'Waiting for',alarm_thread.name)
alarm_thread.join()
print(time.ctime(),'Exiting normally')
在这个例子中,闹铃不会中止use_alarm()中的sleep()调用。
运行结果: