0

I am having a very basic function that takes in a string called name and a callback function. My objective is to be able to terminate from the function, by raising a Keyboard interrupt gracefully.

On the main thread, I am watching for Keyboard interrupt, while foo is running on the background thread.

However at thread.join(), I am running into a threading error.

import threading
import asyncio
import sys
import time

def callback_handler(name):
        print(f"Hi im a callback_handler, my name is {name}")

async def foo(name, cb):
        await asyncio.sleep(5)
        print("Inside foo")
        if cb:
                await asyncio.sleep(5)
                cb(name)


event_loop = asyncio.new_event_loop()
task = event_loop.create_task(foo("bar", callback_handler))
thread = threading.Thread(target=event_loop.run_forever, daemon=True)
thread.start()


try:
        while True:
                message = input("> ")
except (KeyboardInterrupt, EOFError):
        print('Received KeyboardInterrupt')

thread.join()

Error:

python3 cb.py
> ^CReceived KeyboardInterrupt
^CTraceback (most recent call last):
  File "/Users/lamathe/Desktop/cb.py", line 34, in <module>
    thread.join()
  File "/usr/local/Cellar/python@3.9/3.9.13_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/threading.py", line 1060, in join
    self._wait_for_tstate_lock()
  File "/usr/local/Cellar/python@3.9/3.9.13_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/threading.py", line 1080, in _wait_for_tstate_lock
    if lock.acquire(block, timeout):
KeyboardInterrupt

Would highly appreciate any support on this.

Solo Bird
  • 45
  • 1
  • 6
  • you should run `event_loop.stop()` to stop code `run_forever` inside `thread`. Without `stop()` function `run_forever()` runs forever and `join()` waits forever, and you have to press `Ctrl+C` two times (I see two `^C` in your error). With `stop()` before `join()` I have to press `Ctrl+C` only once - and it needs few seconds to end code (without second `Ctrl+C`) – furas Oct 28 '22 at 12:44
  • see also [linux - Cannot kill Python script with Ctrl-C - Stack Overflow](https://stackoverflow.com/questions/11815947/cannot-kill-python-script-with-ctrl-c) – furas Oct 28 '22 at 12:53
  • if you use `daemon=True` then maybe you shouldn't use `join()` – furas Oct 28 '22 at 12:57

1 Answers1

0

In other questions like linux - Cannot kill Python script with Ctrl-C - Stack Overflow you can see that Ctrl+C stops only code in main thread but not event_loop in thread`.

As for me you shouldn't use thread.join() if you have daemon=True - and it will automatically kill thread at the end of code.

try:
    while True:
        message = input("> ")
except (KeyboardInterrupt, EOFError):
    print('Received KeyboardInterrupt')

# --- end of code ---

Or you have to stop loop event_loop.stop() and then you can wait for end of thread. But it may need few seconds to stop some functions in loop.

try:
    while True:
        message = input("> ")
except (KeyboardInterrupt, EOFError):
    print('Received KeyboardInterrupt')

print('stop loop')
event_loop.stop()
        
print('wait for join')
thread.join()

# --- end of code ---
furas
  • 134,197
  • 12
  • 106
  • 148