简体   繁体   中英

Is it possible to kill the parent thread from within a child thread in python?

I am using Python 3.5.2 on windows.

I would like to run a python script but guarantee that it will not take more than N seconds. If it does take more than N seconds, an exception should be raised, and the program should exit. Initially I had thought I could just launch a thread at the beginning that waits for N seconds before throwing an exception, but this only manages to throw an exception to the timer thread, not to the parent thread. For example:

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)

This outputs:

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!.

Is this even remotely possible? I realize I could do something like this:

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)

But this method fails if, for example, may_take_a_long_time("B", 60, kill_thread) was called.

So I guess my TL;DR question is, what's the best way to put a time limit on the main thread itself?

You can use _thread.interrupt_main (this module is called thread in Python 2.7):

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

If the parent thread is the root thread, you may want to try 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)

The cleanest way to do this is to have a queue that the parent thread checks on a regular basis. If the child wants to kill the parent, it sends a message (eg "DIE") to the queue. The parent checks the queue and if it sees the message it dies.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM