The simplest interpretation here is to use a daemon thread.
To achieve this in Python, you can make use of multi-threading. For that, there is the threading module.
Your daemon would run in the background, by setting daemon=True when creating the thread.
Below is a simple example of that in action. Your main logic would go in the main function. The while True infinite loop listens for user input and terminates the program once the user input matches some predefined value ("kill" in this case).
import sys
import threading
def main():
print('Main program')
while True:
pass
# Rest of main program
main_thread = threading.Thread(name='main program',
target=main, daemon=True)
main_thread.start()
while True:
if input().lower() == 'kill':
print('Terminating program')
# Add some possible cleanup code here
sys.exit(0)
Take note of this important information from the Python documentation about how daemonic threads are stopped:
Daemon threads are abruptly stopped at shutdown. Their resources (such
as open files, database transactions, etc.) may not be released
properly. If you want your threads to stop gracefully, make them
non-daemonic and use a suitable signalling mechanism such as an Event.
That said, this approach may suffice for your purposes. Depending on your program logic, if some cleanup code is needed, it could be done before exiting -- since once the sys.exit(0) is called, the daemonic thread will be killed abruptly.
A more general solution, however, is to make use of threading.Event.
This is quite a distinct approach to the above in that we create a regular, non-daemonic thread and pass an Event to it. This time, instead of abruptly exiting the program on user input, we set the internal flag of the Event.
In parallel, instead of a while True infinite loop, the main function uses the non-blocking is_set() to break the loop once the Event is set.
import threading
def main(e):
print('Main program')
while not e.is_set():
pass
# Rest of main program
print('Exiting')
# Add some possible cleanup code here
e = threading.Event()
main_thread = threading.Thread(name='main program',
target=main, args=(e,))
main_thread.start()
while True:
if input().lower() == 'kill':
print('Terminating program')
e.set()
break
main_thread.join()
This has two advantages over the daemonic approach described:
- You could easily have multiple
Events and have your program behave in different ways, depending on those events. There is also the blocking Event.wait() you can use instead of Event.is_set().
- Any cleanup code can instead be managed directly by the
main() function.