0

It is general in programming in Python that when I have a function or something which when I call, it blocks my code to proceed. So I think the best way to unblock is using threads but If I need to stop a thread what should I do? I tried this reference and I wrote this simple program:

import threading
from time import sleep
class my_thread(threading.Thread):
    """Thread class with a stop() method. The thread itself has to check
    regularly for the stopped() condition."""

    def __init__(self):
        super(my_thread, self).__init__()
        self._stop_event = threading.Event()

    def stop(self):
        print("stopping the thread")
        self._stop_event.set()

    def stopped(self):
        value=self._stop_event.is_set()
        print("value of stop event is",value)
        return value
    def run(self):
        print("running the thread")
        print("start function startt()")
        self.startt()

    def startt(self):
        print("it is going to wait forever")
        while True:
            #wait forever
            pass
        print("This line never execute")


def main():
    for i in range(0,3):
        print("it is the main function")
        sleep(1)


if __name__+'__main__':
    thr=my_thread()
    thr.start()

    sleep(5)
    thr.stop()
    thr.stopped()
    print("calling the main function")
    main()
    print("Exiting the whole program")

My problem is this program actually stop the thread but after printing the last line the program still runs. What I want is if I call the stop function thr.start() it starts the thread and run #wait forever line and if I call the stop function thr.stop() it stop the whole class and returns from #wait forever line to the main function.

EDIT-- As @a_guest answer I can fix it but my problem is general for example If I had this code instead of while True:

pythoncom.PumpMessages()

(or any other code)

what should I do?

Masoud Rahimi
  • 5,785
  • 15
  • 39
  • 67
  • what you want to do is check for you event instead of the `while True`, and no you can't use 3'rd party blocking calls if you want to have responsive stop, aim to use non-blocking APIs instead like `something.isthereanythingtodo() then something.do() else loop` – user3012759 Aug 08 '17 at 10:00

2 Answers2

1

Instead of

while True:
    ...

you should use

while not self.stopped():
    ...

Then it will break out of the while loop once you stop() the thread.

a_guest
  • 34,165
  • 12
  • 64
  • 118
  • Thanks for the answer but what about a line with blocking like `pythoncom.PumpMessages()` how can I unblock this? – Masoud Rahimi Aug 08 '17 at 08:29
  • I am not familiar with `pythoncom` but to give an example [`Queue.get`](https://docs.python.org/3/library/queue.html#queue.Queue.get) has a `timeout` parameter which can be set in order to make it *not* blocking forever (at most `timeout` seconds). `pythoncom.PumpMessages()` has probably something similar, if not you'll have to find a way around manually, but that's worth another question. – a_guest Aug 08 '17 at 08:38
  • No, I don't want to set a timeout what I want is to exit from blocking line immediately if I call a related function whenever needed. – Masoud Rahimi Aug 08 '17 at 10:10
  • @MasoudR. You can't do that gracefully. Either you kill the thread (on OS basis, Python offers functionality for that) or you wait for the method call to return. No timeout means you'll wait forever. This is due to the internals of the invoked method, nothing you can control in your invoking thread class. – a_guest Aug 08 '17 at 10:21
  • Ok so If I want to use timeout how can I implement? I mean I need to have control for that timeout so when I want to decrease it or something? – Masoud Rahimi Aug 08 '17 at 10:26
  • @MasoudR. If I understood correctly it's about `pythoncom.PumpMessages()`. I'm not familiar with this library nor the method in question. If it offers a timeout parameter - good. If it doesn't maybe you can workaround by exploiting the mechanism of how that method works - but as I said that's worth another question. – a_guest Aug 08 '17 at 10:39
  • Thank you, I replace the `pythoncom.PumpMessages()` with `pythoncom.PumpWaitingMessages()` inside the loop and my problem solved. I got into another problem with it but I created another question. – Masoud Rahimi Aug 10 '17 at 09:35
1

You can't "abort" a running thread so to stop it you'll have to have a mechanism in the thread itself that periodically checks if it should stop.

Regular threads keep running while the rest of your program (process) exits. If you make your thread a 'daemon' thread however, it will get killed automatically when your program exits. To do that, set self.daemon=True in your thread's init method. More info https://docs.python.org/3/library/threading.html#threading.Thread.daemon

Irmen de Jong
  • 2,739
  • 1
  • 14
  • 26
  • Thanks but if I use daemon it terminates the whole program, suppose that In my main() function I have a while True that must run forever how about that? – Masoud Rahimi Aug 08 '17 at 10:24
  • I am afraid I don't understand your question. Ofcourse you have to have *something* that is running or waiting on something? If there's nothing to run, the program stops, obviously. – Irmen de Jong Aug 08 '17 at 11:00
  • @IrmendeJong I guess the question was about how to terminate a specific thread (which is stuck in a blocking call) from the main thread while the latter is still running. – a_guest Aug 08 '17 at 11:33
  • @IrmendeJong so how do I figure it out? – Masoud Rahimi Aug 09 '17 at 06:34
  • restructure your code in such a way that you don't need to forcefully abort a thread (because that is impossible). Give the thread a loop of some sort or a signal that it can check to see if it should stop running.. – Irmen de Jong Aug 09 '17 at 11:09