是否有可能从python中的子线程中杀死父线程?

时间:2016-09-02 16:38:46

标签: python multithreading time

我在Windows上使用Python 3.5.2。

我想运行一个python脚本,但保证它不会超过 N 秒。如果 超过 N 秒,则应引发异常,程序应退出。最初我曾想过我可以在开始时启动一个线程,在抛出异常之前等待 N 秒,但这只会设法向定时器线程抛出异常,而不是父线程。例如:

import threading
import time

def may_take_a_long_time(name, wait_time):
    print("{} started...".format(name))
    time.sleep(wait_time)
    print("{} finished!.".format(name))

def kill():
    time.sleep(3)
    raise TimeoutError("No more time!")

kill_thread = threading.Thread(target=kill)
kill_thread.start()

may_take_a_long_time("A", 2)
may_take_a_long_time("B", 2)
may_take_a_long_time("C", 2)
may_take_a_long_time("D", 2)

输出:

A started...
A finished!.
B started...
Exception in thread Thread-1:
Traceback (most recent call last):
    File "C:\Program Files\Python35\lib\threading.py", line 914, in _bootstrap_inner
    self.run()
    File "C:\Program Files\Python35\lib\threading.py", line 862, in run
    self._target(*self._args, **self._kwargs)
    File "timeout.py", line 11, in kill
    raise TimeoutError("No more time!")
    TimeoutError: No more time!

B finished!.
C started...
C finished!.
D started...
D finished!.

这甚至可以远程实现吗?我意识到我可以做这样的事情:

import threading
import time

def may_take_a_long_time(name, wait_time, thread):
    if not thread.is_alive():
        return
    print("{} started...".format(name))
    time.sleep(wait_time)
    print("{} finished!.".format(name))

def kill():
    time.sleep(3)
    raise TimeoutError("No more time!")

kill_thread = threading.Thread(target=kill)
kill_thread.start()

may_take_a_long_time("A", 2, kill_thread)
may_take_a_long_time("B", 2, kill_thread)
may_take_a_long_time("C", 2, kill_thread)
may_take_a_long_time("D", 2, kill_thread)

但是,如果调用may_take_a_long_time("B", 60, kill_thread),则此方法失败。

所以我猜我的TL; DR问题是,对主线程本身设置时间限制的最佳方法是什么?

3 个答案:

答案 0 :(得分:6)

您可以使用_thread.interrupt_main(此模块在Python 2.7中称为thread):

import time, threading, _thread

def long_running():
    while True:
        print('Hello')

def stopper(sec):
    time.sleep(sec)
    print('Exiting...')
    _thread.interrupt_main()

threading.Thread(target = stopper, args = (2, )).start()

long_running()

答案 1 :(得分:2)

如果父线程是根线程,您可能想尝试os._exit(0)

import os
import threading
import time

def may_take_a_long_time(name, wait_time):
    print("{} started...".format(name))
    time.sleep(wait_time)
    print("{} finished!.".format(name))

def kill():
    time.sleep(3)
    os._exit(0)

kill_thread = threading.Thread(target=kill)
kill_thread.start()

may_take_a_long_time("A", 2)
may_take_a_long_time("B", 2)
may_take_a_long_time("C", 2)
may_take_a_long_time("D", 2)

答案 2 :(得分:-1)

最简洁的方法是拥有一个父线程定期检查的队列。如果孩子想要杀死父母,它会向队列发送一条消息(例如“DIE”)。父进程检查队列,如果看到消息,它就死掉。

    q = queue.Queue()
    bc = queue.Queue()          # backchannel

    def worker():
    while True:
            key = q.get()
            try:
                process_key(key)
            except ValueError as e:
                bc.put('DIE')
            q.task_done()

    # Start the threads
    for i in range(args.threads):
        threading.Thread(target=worker, daemon=True).start()

    for obj in object_farm():
        q.put(obj)
        try:
            back = bc.get(block=False)
        except queue.Empty:
            pass
        else:
            print("Data received on backchannel:",back)
            if back=='DIE':
                raise RuntimeError("time to die")