Terminating main thread from child thread - python

I have a GUI thread and Main thread. After closing a window I have method called inside the GUI thread. I would like to propagate this to Main thread to end its work. Main thread is doing several steps, so I am able to set stop_event, but I do not want to check after each line of code for Main thread if stop_event is set.
Thank you for your advices.

If your purpose is just to terminate main thread from the child thread, try the below.
import threading
import signal
import time
import os
def main():
threading.Thread(target=child).start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt as e:
# KeyboardInterrupt happens by `signal.SIGINT` from the child thread.
print('Main thread handle something before it exits')
print('End main')
def child():
print('Run child')
time.sleep(2)
# Send a signal `signal.SIGINT` to main thread.
# The signal only head for main thread.
os.kill(os.getpid(), signal.SIGINT)
print('End child')
if __name__ == '__main__':
main()

Related

Why is Python3 daemon thread instantly closing in console?

this code works in idle3 but in a console(MAC, Windows Linux) thread2 is instantly closing if set to daemon. Is there any explanation for that ? Maybe also a workaround to properly have a daemon thread asking for user input ?
import queue
import threading
import sys
def worker(q):
_text = ''
while _text == '':
_text = q.get()
print('[worker]input was ',_text)
sys.exit()
def dialog(q):
while True:
try:
_select = input('[dialog]enter text:')
if _select != '':
q.put(_select)
except EOFError:
pass
except KeyboardInterrupt:
print("bye")
sys.exit(0)
except Exception as e:
print(e)
sys.exit(1)
if 'esc'.lower() in _select.lower():
sys.exit()
q = queue.Queue()
thread1 = threading.Thread(target=worker,args=(q,))
thread2 = threading.Thread(target=dialog,args=(q,))
thread1.setDaemon(True)
thread2.setDaemon(True)
print('start asking')
thread1.start()
thread2.start()
thanks for any hint on the issue
Normally the child threads die when the main thread exits. The code you've given as example exits directly after starting two child threads. To solve this, you should 'join' the threads back to the main thread. This will make it so the main thread waits for the child threads to die.
thread1.join()
thread2.join()
at the end of your file should solve this problem.
https://docs.python.org/3.5/library/threading.html#threading.Thread.join
Also, why do you want to run this application as daemon?

Terminate GObject.Mainloop() threads together with main

I have the following two threads:
myThread = threading.Thread(target=sender.mainloop.run, daemon=True)
myThread.start()
myThread2 = threading.Thread(target=receiver.mainloop.run, daemon=True)
myThread2.start()
The targets are GObject.Mainloop() methods.
Afterwards my main program is in an infinite loop.
My problem is that when the execution is terminated by CTRL-C, Keyboardexception is raised for both threads, but the main program does not terminate.
Any ideas how could both the main program and the two threads be terminated by CTRL-C?
ctrl-c issues a SIGINT signal, which you can capture in your main thread for a callback. You can then run whatever shutdown code you want in the callback, maybe a sender/receiver.mainloop.quit() or something.
import threading
import signal
import sys
def loop():
while True:
pass
def exit(signal, frame):
sys.exit(0)
myThread = threading.Thread(target=loop)
myThread.daemon = True
myThread.start()
myThread2 = threading.Thread(target=loop)
myThread2.daemon = True
myThread2.start()
signal.signal(signal.SIGINT, exit)
loop()

Why is signal.SIGTERM not dealt with properly in my main thread?

I have python code which runs continuously (collecting sensor data). It is supposed to be launched at boot using start-stop-daemon. However, I'd like to be able to kill the process gracefully, so I've started from the advice in the post How to process SIGTERM signal gracefully? and put my main loop in a separate thread. I'd like to be able to gracefully shut it down both when it is running as a daemon (the start-stop-daemon will send a kill signal) and when I launch it briefly for testing in a terminal myself (me pressing ctrl-c).
However, the signal handler doesn't seem to be called if I kill the process (even without using the thread, the "done (killed)" never ends up in the file I've redirected to). And when I press ctrl-c, the collecting just continues and keeps printing data in the terminal (or to the file I am redirecting to).
What am I doing wrong in the following code?
from threading import Thread
import time, sys, signal
shutdown_flag = False #used for gracefull shutdown
def main_loop():
while not shutdown_flag:
collect_data() # contains some print "data" statements
time.sleep(5)
print "done (killed)"
def sighandler(signum, frame):
print 'signal handler called with signal: %s ' % signum
global shutdown_flag
shutdown_flag = True
def main(argv=None):
signal.signal(signal.SIGTERM, sighandler) # so we can handle kill gracefully
signal.signal(signal.SIGINT, sighandler) # so we can handle ctrl-c
try:
Thread(target=main_loop, args=()).start()
except Exception, reason:
print reason
if __name__ == '__main__':
sys.exit(main(sys.argv))
You are terminating your main thread with this statement:
if __name__ == '__main__':
sys.exit(main(sys.argv))
So your signal handler never gets to run. The signal handler is part of the main thread not the main_loop thread you created. So once the main thread exits there's no signal handler function to call anymore.
You need something like this:
def sighandler(signum, frame):
print 'signal handler called with signal: %s ' % signum
global shutdown_flag
shutdown_flag = True
sys.exit() # make sure you add this so the main thread exits as well.
if __name__ == '__main__':
main(sys.argv)
while 1: # this will force your main thread to live until you terminate it.
time.sleep(1)
A simple test to see how many threads are running in your program is this:
def main_loop():
while not shutdown_flag:
collect_data() # contains some print "data" statements
time.sleep(5)
import threading
print threading.enumerate()
print "done (killed)"

Python program with thread can't catch CTRL+C

I am writing a python script that needs to run a thread which listens to a network socket.
I'm having trouble with killing it using Ctrl+c using the code below:
#!/usr/bin/python
import signal, sys, threading
THREADS = []
def handler(signal, frame):
global THREADS
print "Ctrl-C.... Exiting"
for t in THREADS:
t.alive = False
sys.exit(0)
class thread(threading.Thread):
def __init__(self):
self.alive = True
threading.Thread.__init__(self)
def run(self):
while self.alive:
# do something
pass
def main():
global THREADS
t = thread()
t.start()
THREADS.append(t)
if __name__ == '__main__':
signal.signal(signal.SIGINT, handler)
main()
Appreciate any advise on how to catch Ctrl+c and terminate the script.
The issue is that after the execution falls off the main thread (after main() returned), the threading module will pause, waiting for the other threads to finish, using locks; and locks cannot be interrupted with signals. This is the case in Python 2.x at least.
One easy fix is to avoid falling off the main thread, by adding an infinite loop that calls some function that sleeps until some action is available, like select.select(). If you don't need the main thread to do anything at all, use signal.pause(). Example:
if __name__ == '__main__':
signal.signal(signal.SIGINT, handler)
main()
while True: # added
signal.pause() # added
It's because signals can only be caught by main thread. And here main thread ended his life long time ago (application is waiting for your thread to finish). Try adding
while True:
sleep(1)
to the end of your main() (and of course from time import sleep at the very top).
or as Kevin said:
for t in THREADS:
t.join(1) # join with timeout. Without timeout signal cannot be caught.

python: can't terminate a thread hung in socket.recvfrom() call

I cannot get a way to terminate a thread that is hung in a socket.recvfrom() call. For example, ctrl+c that should trigger KeyboardInterrupt exception can't be caught. Here is a script I've used for testing:
from socket import *
from threading import Thread
from sys import exit
class TestThread(Thread):
def __init__(self,host="localhost",port=9999):
self.sock = socket(AF_INET,SOCK_DGRAM)
self.sock.bind((host,port))
super(TestThread,self).__init__()
def run(self):
while True:
try:
recv_data,addr = self.sock.recvfrom(1024)
except (KeyboardInterrupt, SystemExit):
sys.exit()
if __name__ == "__main__":
server_thread = TestThread()
server_thread.start()
while True: pass
The main thread (the one that executes infinite loop) exits. However the thread that I explicitly create, keeps hanging in recvfrom().
Please, help me resolve this.
Keyboard interrupts are always caught on the main thread -- never on "child" threads. To avoid server_thread keeping the process alive when the main thread exits, do
server_thread.daemon = True
before you call server_thread.start().
BTW, your while True: pass in the main thread is needlessly burning CPU cycles. You should at least change it to something like while True: time.sleep(1.0). But that doesn't change the semantics of your code -- just gets it down from 99% CPU or so, to (I'd guess) < 5%;-).
You should open a pipe from the main thread to the network thread and 'select' on both the socket and the pipe. When you want to terminate the network thread, just send a byte through the pipe from the main thread and act accordingly in the network thread.
Just my 2 cents.

Categories