Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interrupting a thread in Python with a KeyboardException in the main thread

I have a few classes that look more or less like this:

import threading
import time

class Foo():
    def __init__(self, interval, callbacks):
        self.thread = threading.Thread(target=self.loop)
        self.interval = interval
        self.thread_stop = threading.Event()
        self.callbacks = callbacks

    def loop():
        while not self.thread_stop.is_set():
            #do some stuff...
            for callback in self.callbacks():
                callback()
            time.sleep(self.interval)

    def start(self):
        self.thread.start()

    def kill(self):
        self.thread_stop.set()

Which I am using from my main thread like this:

interval = someinterval
callbacks = [some callbacks]

f = Foo(interval, callbacks)

try:
    f.start()
except KeyboardInterrupt:
    f.kill()
    raise

I would like a KeyboardInterrupt to kill the thread after all the callbacks have been completed, but before the loop repeats. Currently they are ignored and I have to resort to killing the terminal process that the program is running in.

I saw the idea of using threading.Event from this post, but it appears like I'm doing it incorrectly, and it's making working on this project a pretty large hassle.

I don't know if it may be relevant, but the callbacks I'm passing access data from the Internet and make heavy use of the retrying decorator to deal with unreliable connections.


EDIT

After everyone's help, the loop now looks like this inside Foo:

    def thread_loop(self):
        while not self.thread_stop.is_set():
            # do some stuff
            # call the callbacks
            self.thread_stop.wait(self.interval)

This is kind of a solution, although it isn't ideal. This code runs on PythonAnywhere and the price of the account is by CPU time. I'll have to see how much this uses over the course of a day with the constant waking and sleeping of threads, but it at least solves the main issue

like image 626
Jon Cohen Avatar asked Apr 14 '15 17:04

Jon Cohen


People also ask

Can Python can execute multiple instructions simultaneously by using threads?

To recap, threading in Python allows multiple threads to be created within a single process, but due to GIL, none of them will ever run at the exact same time. Threading is still a very good option when it comes to running multiple I/O bound tasks concurrently.

What is a threading Active_count () in Python?

In Python, the method threading. active_co unt() from the threading module is used to count the currently active or running threads.


1 Answers

I think your problem is that you have a try-except-block around f.start(), but that returns immediately, so you aren't going to catch KeyboardInterrupts after the thread was started.

You could try adding a while-loop at the bottom of your program like this:

f.start()
try:
    while True:
        time.sleep(0.1)
except KeyboardInterrupt:
    f.kill()
    raise

This isn't exactly the most elegant solution, but it should work.

like image 200
jazzpi Avatar answered Oct 03 '22 11:10

jazzpi