python多线程join方法导致不能接收信号

今天写一个小工具,开启多个线程,在子线程里循环执行任务,发现不能退出程序,然后折腾了半天,还是退出不了,最后发现,原来是个bug


先上简化了的代码:

import sys
import threading
import signal
import time


class myThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
    def run(self):
        while True:
            time.sleep(1)
def handler(signum, frame):
    print("exit")
    sys.exit()

if __name__ == "__main__":
    signal.signal(signal.SIGINT, handler)
    threads = []
    for _ in range(0,2):
        t = myThread()
        t.setDaemon(True)
        threads.append(t)
        t.start()
    for _ in range(0,2):
        t.join()
    # while True:pass

主线程里开启了两个子线程,子线程啥事都不干,醒了就睡,睡醒了接着睡,如此循环往复。并将它们设为daemon线程,

按我的理解daemon线程就是指当主线程代码执行完退出后,那么daemon子线程也会结束任务并退出,而非daemon线程会不管主线程,它会一如既往的执行自己的任务,直到结束才退出,当所有线程都退出了,那么这个进程就结束了。。

主线程注册了一个SIGINT信号,当接收到这个信号就退出主线程,ctr+c就向这个主线程发送SIGINT信号,然后按照这个流程,当按下ctr+c的时候应该打印exit后退出进程,然后什么事情都没发生。。

然后查资料发现这居然是一个bug,我的天。详细地址:https://bugs.python.org/issue1167930

当主线程join并且子线程没有结束的时候,会阻塞在那,而且不会接受任何信号。。

然而这个bug他们并没有修复,只是建议用timeout参数来规避。。


更奇怪的是,python3(我用的3.4)却没有这个bug,join的时候,按下ctr+c可以正常退出进程,上面代码可以直接用python3执行,看来是在python3中把这个问题修复了,至于python2为啥没修复就不知道了,也许有什么难言的苦衷吧,(好象是修复bug会导致其它问题)。。


网上有很多解决办法,但是一眼看上去有点复杂,我想如果主线程不使用join,而是使用一个while循环挂在那,当然后让主线程退出了,子线程也就推出了。

试验了一下没问题:

import sys
import threading
import signal
import time

class myThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        while True:
            time.sleep(1)

def handler(signum, frame):
    print("exit")
    sys.exit()


if __name__ == "__main__":

    signal.signal(signal.SIGINT, handler)
    threads = []
    for _ in range(0,2):
        t = myThread()
        t.setDaemon(True)
        threads.append(t)
        t.start()
    # for _ in range(0,2):
    #     t.join()
    while True:
        time.sleep(1)


本人出于个人兴趣,创建了一个个人公众号,每天筛选国外网友发现的有趣的事情推送到公众号,欢迎关注!

python多线程join方法导致不能接收信号_第1张图片


你可能感兴趣的:(python)