Python: prevent signals to propagate to child threads

最后都变了- 提交于 2019-12-11 05:09:29

问题


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()

if i press ^C while the threads are running, does the thread gets the SIGINT?
if this is true, what can i do from the caller thread to stop it from propagating SIGINT to running threads?

signal handler in caller thread would prevent it?
or do i need signal handler for each thread?


回答1:


As referred in Python's docs, you should use the attribute daemon:

daemon: A boolean value indicating whether this thread is a daemon thread (True) or not (False). This must be set before start() is called, otherwise RuntimeError is raised. Its initial value is inherited from the creating thread; the main thread is not a daemon thread and therefore all threads created in the main thread default to daemon = False.

The entire Python program exits when no alive non-daemon threads are left.

New in version 2.6.

To control the CTRL+C signal, you should capture it changing the handler with the signal.signal(signal_number, handler) function. The child process inherits the signal handler for 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()



回答2:


if i press ^C while the threads are running, does the thread gets the SIGINT?

No. In Python, only the main thread receives the SIGINT.

Unfortunately, I don't know of a good place in the python source or docs to link to, but you can see that this is true with a simple test:

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)

After you send SIGINT with ^C, you will see that the main thread is killed (no more 'Parent parenting' logs) and the child thread continues to run.

In your example, your child threads exit because you break out of their while loops after 10 seconds.



来源:https://stackoverflow.com/questions/38596069/python-prevent-signals-to-propagate-to-child-threads

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!