【问题标题】:Python: prevent signals to propagate to child threadsPython:防止信号传播到子线程
【发布时间】: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 到正在运行的线程?

调用者线程中的信号处理程序会阻止它吗?
还是我需要每个线程的信号处理程序?

【问题讨论】:

    标签: python multithreading signals


    【解决方案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 循环。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-29
      • 2015-09-30
      相关资源
      最近更新 更多