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)

python 守护进程

ReactJS setState 更改不会从父组件传播到子组件[重复]

从主线程发送信号给子线程,子线程里的connect函数怎么个写法

在 Core Data 中执行子获取时,在父上下文中修改托管对象是不是会向下传播到子上下文?