Python:防止信号传播到子线程
Posted
技术标签:
【中文标题】Python:防止信号传播到子线程【英文标题】:Python: prevent signals to propagate to child threads 【发布时间】:2016-07-26 17:11:27 【问题描述】:import threading
import time
def worker(i):
while True:
try:
print i
time.sleep(10)
break
except Exception, msg:
print msg
threads = []
for i in range(10):
t1 = threading.Thread(target=worker, args=(i,))
threads.append(t1)
for t in threads:
t.start()
print "started all threads... waiting to be finished"
for t in threads:
t.join()
如果我在线程运行时按 ^C,线程会获得 SIGINT 吗? 如果这是真的,我可以从调用者线程做些什么来阻止它传播 SIGINT 到正在运行的线程?
调用者线程中的信号处理程序会阻止它吗? 还是我需要每个线程的信号处理程序?
【问题讨论】:
【参考方案1】:如Python's docs 中所述,您应该使用属性daemon:
daemon:一个布尔值,指示此线程是否为守护进程 线程(真)或不(假)。这必须在 start() 之前设置 调用,否则引发 RuntimeError。它的初始值为 从创建线程继承;主线程不是守护进程 线程,因此在主线程中创建的所有线程默认为 守护进程 = False。
当没有存活的非守护线程时整个 Python 程序退出 离开了。
2.6 版中的新功能。
要控制 CTRL+C 信号,您应该使用 signal.signal(signal_number, handler) 函数更改处理程序来捕获它。子进程继承 SIGINT 的信号处理程序。
import threading
import time
import signal
def worker(i):
while True:
try:
print(i)
time.sleep(10)
break
except Exception as msg:
print(msg)
def signal_handler(signal, frame):
print('You pressed Ctrl+C!')
print("I will wait for all threads... waiting to be finished")
for t in threads:
t.join()
signal.signal(signal.SIGINT, signal_handler)
threads = []
for i in range(10):
t1 = threading.Thread(target=worker, args=(i,))
threads.append(t1)
for t in threads:
t.start()
print("started all threads... waiting to be finished")
for t in threads:
t.join()
【讨论】:
我想明确加入他们。 如果子线程继承了信号处理程序,每个线程会尝试加入线程(列表)吗? for t in thread: t.join() 是该块调用一次还是由所有线程调用?【参考方案2】:如果我在线程运行时按 ^C,线程会得到 SIGINT 吗?
没有。在 Python 中,只有主线程接收 SIGINT。
不幸的是,我不知道在 python 源代码或文档中链接的好地方,但您可以通过一个简单的测试看到这是正确的:
import threading
import time
def worker():
while True:
print('Worker working')
time.sleep(0.5)
pass
worker_thread = threading.Thread(target=worker)
worker_thread.start()
while True:
print('Parent parenting')
time.sleep(0.5)
在您使用 ^C 发送 SIGINT 后,您将看到主线程被终止(不再有 'Parent parenting' 日志)并且子线程继续运行。
在您的示例中,您的子线程退出是因为您 break
在 10 秒后退出了它们的 while
循环。
【讨论】:
以上是关于Python:防止信号传播到子线程的主要内容,如果未能解决你的问题,请参考以下文章
Spring将请求范围的bean提升到子线程(HttpServletRequest)
ReactJS setState 更改不会从父组件传播到子组件[重复]