2

I am looking for a way to raise an exception in a while True loop. The signal to raise the exception origins in a thread t_run which continuously checks a global boolean variable called pingresponse. As soon as pingresponse equals "False" the while True loop should immediately be interrupted. What I don't want is to continuously check the variable pingresponse in the while True loop to check if the exception has to be raised.

My draft so far looks as follows:

import time
import threading
import random

def run():
    # this thread continuously checks the pingresponse
    global pingresponse

    while True:
        # simulating a random pingresponse
        if random.random() > 0.8:
            pingresponse = False
        else:
            pingresponse = True
        time.sleep(0.001)

pingresponse = True
t_run = threading.Thread(target=run)
t_run.start()

while True:
    i = 0
    while True:
        try:
            print('While True loop iteration', i)
            print('pingresponse:' ,pingresponse)
            i += 1

            # "do some work" which includes several consecutive and encapsulated while and for loops
            time.sleep(1) # simulate "do some work" and prevent infinite looping if executed

            # What I want is immediately interrupting the inner while True loop by raising an exception
            # as soon as pingresponse was set to False in the t_run thread
            # The exception should be raised independently of the current position in "do some work"

            # What I don't want is to check the pingresponse variable all the time in "do some work":
            # if not pingresponse:
            #   raise Exception

        except Exception:
            print('pingresponse was set to False in the t_run thread')
            print('start while True loop again with iteration 0')
            break
Jonas
  • 121,568
  • 97
  • 310
  • 388
user111029
  • 23
  • 4
  • Does this answer your question? [Catch a thread's exception in the caller thread in Python](https://stackoverflow.com/questions/2829329/catch-a-threads-exception-in-the-caller-thread-in-python) – Akihito KIRISAKI Dec 26 '20 at 14:42
  • Related: [Stop a main thread from child thread](https://stackoverflow.com/questions/16493042/stop-a-main-thread-from-child-thread) , [How to exit the entire application from a Python thread?](https://stackoverflow.com/questions/1489669/how-to-exit-the-entire-application-from-a-python-thread) , – wwii Dec 26 '20 at 15:35
  • If any of the linked Q&A's answer your question, let us know so we can mark yours as a duplicate - and don't accept my answer (I'll delete it). – wwii Dec 26 '20 at 16:02
  • I don't know why you modified my example to "stop everything" but the _thread.interrupt_main() function to throw a Keyboard interrupt is a possible solution to my problem. – user111029 Dec 26 '20 at 17:13
  • @user111029 I did that so it would stop *for me* while playing around - I didn't want the infinite loop(s) hanging *out there*. – wwii Dec 26 '20 at 17:26

1 Answers1

1

Using method from this answer to How to exit the entire application from a Python thread?. Modified your example to stop everything when the exception occurs. _thread.interrupt_main() will throw a Keyboard interrupt in the main thread.

import time
import threading
import _thread
import random

def run():
    # this thread continously checks the pingresponse
    global pingresponse

    while True:
        # simulating a random pingresponse
        x = random.random()
        print(f'x:{x:1.3f}')
        if x > 0.98:
            pingresponse = False
        else:
            pingresponse = True
        time.sleep(0.001)
        if not pingresponse:
            _thread.interrupt_main()
            break

pingresponse = True
t_run = threading.Thread(target=run)
t_run.start()

foo = True
while foo:
    i = 0
    while True:
        try:
            print('While True loop iteration', i)
            print('pingresponse:' ,pingresponse)
            i += 1

            # "do some work" which includes several consecutive and encapsulated while and for loops
            time.sleep(1) # simulate "do some work" and prevent infinite looping if executed

        except KeyboardInterrupt as e:
            print('pingresponse was set to False in the t_run thread')
            print('start while True loop again with iteration 0')
            # print(e)
            foo = False
            # raise
            break
    if foo: break

There may be things you need to consider if using _thread.interrupt_main() - you should spend some time researching that. Might want to include the signal module in that journey.
How do I capture SIGINT in Python? looks worthwhile.

wwii
  • 23,232
  • 7
  • 37
  • 77