threading Timer - use timer to 'sys.exit' main thread - python

I would like to use Timer to exit a script where an infinite loop is running.
Here is a simple stub that I created to test that logic:
import threading
import sys
import time
def exit():
sys.exit()
if __name__ == '__main__':
t = threading.Timer(3, exit)
t.start()
while True:
time.sleep(3)
This doesn't make the script to sys.exit though.
Any pointer why, and how can i achieve the Timer to sys.exit the main thread?

Related

How to terminate a loop early in in a thread?

I have a loop which makes a get request to a webservice to fetch data and do some stuff, but I want to 'manually' terminate the thread/event, which I achieved with the following example:
from threading import Event
exit = Event()
if external_condition():
exit.set()
for _ in range(mins):
fetch_data_and_do_stuff()
exit.wait(10) #wait 10 seconds
With that, the only thing that terminates it's the sleep time between loops. How can I also kill the loop so it doesn't keep running until it gets to the last iteration?
nvm i've solved it like this
from threading import Event
exit = Event()
if external_condition():
exit.set()
for _ in range(mins):
fetch_data_and_do_stuff()
if exit.wait(10):
break
the condition returns true when killed and also sleeps the 10 seconds, so it works
you have 2 options ,
kill the thread or process entirely
or making the loop's boolean false. going that way
you could use a global variable in this way: [Python 3.7] , run it to see
from threading import Thread
from time import sleep
global glob
glob=True
def threaded_function():
while glob:
print("\n [Thread] this thread is running until main function halts this")
sleep(0.8)
if __name__ == "__main__":
thread = Thread(target = threaded_function, args = ())
thread.start()
for i in range(4,0,-1):
print("\n [Main] thread will be terminated in "+str(i)+" seconds")
sleep(1)
glob=False
while True:
print("[Main] program is over")
sleep(1)

Need to call exit() twice to exit when working with thread and signal handler

I stumble upon pice of code that is a bit werid, I'm expecting when the program is signaled, the exit() should raise SystemExit once and cause the program to exit, however in this case, when the main thread is blocking on th.join(), the exit() statement needs be called twice for the program to exit.
It is not a practical exercise, but I want to know what is going on under the hood.
import threading
import time
import signal
def task():
while True:
time.sleep(1)
def sig_handler(self, *_):
# raise ValueError()
exit()
def main():
signal.signal(signal.SIGINT, sig_handler)
th = threading.Thread(target=task)
th.start()
th.join()
if __name__ == "__main__":
main()
Usually, our main program implicitly waits until all other threads have completed their work. Using daemon threads is useful for services where there may not be an easy way to interrupt the thread or where letting the thread die in the middle of its work without losing or corrupting data. to set a thread as a daemon that runs without blocking the main program from exiting. use setDaemon() method. Your main function will be:
def main():
signal.signal(signal.SIGINT, sig_handler)
th = threading.Thread(target=task)
th.setDaemon(True)
th.start()
th.join()

pynput keyboard listener causes delays

I am making a program that toggles on and off by a certain key on the keyboard (using pynput). I placed the keyboard listener loop in the first thread, and the action loop in the second.
The problem is that after I start the code, it doesn't listen to the keyboard immediately, only after 9-10 seconds have passed. And sometimes it refuses to react to Esc button, and sometimes it works. How to fix the lag? Is the code ok?
from threading import Thread
from pynput import keyboard
import time
flag = False
kill = False
def on_press(key):
global flag
global kill
if key == keyboard.KeyCode.from_char('a'):
print('pressed A')
flag = not flag
if key == keyboard.Key.esc:
kill = True
return False
def thr2():
print('joining...')
with keyboard.Listener(on_press=on_press) as listen:
listen.join()
def thr1():
while True:
if kill:
break
if flag:
print('looping....')
time.sleep(0.4)
if __name__ == "__main__":
thread1 = Thread(target=thr1)
thread2 = Thread(target=thr2)
thread1.start()
thread2.start()
It looks like the actual delay is coming from the pynput keyboard.Listener context handler itself. I can't tell you whats happening under the hood but the delay is not coming from the way you are managing your threads.
# pynput library creating keyboard.Listener thread causes the delay
with keyboard.Listener(on_press=on_press) as listen:
print('listen thread created') # This does not happen until after the delay
listen.join()
You may want to rephrase the question so that it is specific to pynput keyboard.Listener
Here is a solution that works nicely with multiprocessing:
import sys
from pynput import keyboard
from time import sleep
from multiprocessing import Process, Event
from functools import partial
def thr2(kill_event, flag_event):
def on_press(kill_event, flag_event, key):
if key == keyboard.KeyCode.from_char('a'):
print('pressed A')
if flag_event.is_set():
flag_event.clear()
else:
flag_event.set()
if key == keyboard.Key.esc:
print('esc')
kill_event.set()
sys.exit(0)
with keyboard.Listener(on_press=partial(on_press, kill_event, flag_event)) as listen:
listen.join()
def thr1(kill_event, flag_event):
while True:
if kill_event.is_set():
print('kill')
sys.exit(0)
if flag_event.is_set():
print('looping....')
sleep(0.4)
if __name__ == "__main__":
kill_event = Event()
flag_event = Event()
thread1 = Process(target=thr1, args=(kill_event, flag_event))
thread2 = Process(target=thr2, args=(kill_event, flag_event))
thread1.start()
thread2.start()
thread1.join() # Join processes here to avoid main process exit
thread2.join()

I need to stop multi thread code from running

I'm trying to stop the code from running if the user presses ctrl+shift+c. I use the code below. Unfortunately sys.exit() stops only "wait_for_ctrl_shift_c" function, but not "main_func". What should I use to stop them both?
Thanks.
def wait_for_ctrl_shift_c():
print ('wait_for_ctrl_shift_c is working')
keyboard.wait('ctrl+shift+c')
print('wait_for_ctrl_shift_c was pressed!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
sys.exit()
def main_func():
a=0
while True:
print ('Working2 ',a)
a=a+1
sleep(1)
if __name__ == '__main__':
Thread(target = wait_for_ctrl_shift_c).start()
Thread(target = main_func).start()
There are multiple ways to do it. First of all you have 3 threads, one main thread and the other 2 (infinite loop & keyboard one) you create.
You can register signals and handle it, also you can call interrupt_main to interrupt main thread (not the while loop thread). Interrupt will go to main exception handler. Also instead of True i changed the second thread to have an attribute to check if it should run for clean exit.
import os
import threading
import time
import sys
import _thread
def wait_for_ctrl_shift_c():
print ('wait_for_ctrl_shift_c is working')
keyboard.wait('ctrl+shift+c')
print ('exiting thread')
_thread.interrupt_main()
sys.exit()
def main_func():
a=0
t = threading.currentThread()
while getattr(t, "run", True):
print ('Working2 ',a)
a=a+1
time.sleep(1)
print ('exiting main_func')
if __name__ == '__main__':
try:
t1 = threading.Thread(target = wait_for_ctrl_shift_c)
t2 = threading.Thread(target = main_func)
t1.start()
t2.start()
t1.join()
t2.join()
except:
print ('main exiting')
t2.run = False
sys.exit()
Open shell in another window, type ps to list running processes, and kill the Python one (via kill 3145, if 3145 is its PID) to stop them both. This way we kill the process within which these threads run.

Unable to remove lockfile

I'm trying to use zc.lockfile. I see that a lockfile is created in the same directory as my python script, but when I press ctrl+C, the file is NOT removed. I have a callback registered and have even tested given a long time (not sure if zc.lockfile spawns a new thread and needed time to complete).
import os
import sys
import signal
import time
import zc.lockfile
program_lock = None
def onExitCodePressed(signal, frame):
"""Callback run on a premature user exit."""
global program_lock
print '\r\nYou pressed Ctrl+C'
program_lock.close()
time.sleep(5)
sys.exit(0)
def main():
signal.signal(signal.SIGINT, onExitCodePressed)
if os.path.exists('myapp_lock'):
print "\nAnother instance of the program is already running.\n"
sys.exit(0)
else:
program_lock = zc.lockfile.LockFile('myapp_lock')
while True:
continue
if __name__ == '__main__':
main()

Categories

Resources