I would like to kill somehow a running thread from my GUI application via setting an event, but I can't use a for loop in my thread so I need some other solution to check the event
I have the following situation.
In a tkinter gui when I click a button I start a thread and set a global variable.
self.thread = StoppableThread(caller=self)
self.thread.start()
is_running = 1
When I next click the button I check the global variable state and if it is already set I send a stop request:
if is_running:
is_running = 0
self.thread.stop()
This is my thread class:
import threading
from time import sleep
class StoppableThread(threading.Thread):
def __init__(self, caller=None):
super(StoppableThread, self).__init__()
self._stop_event = threading.Event()
self.caller = caller
def stop(self):
self._stop_event.set()
def stopped(self):
return self._stop_event.is_set()
def run(self) -> None:
while True:
# check for stop
if self.stopped():
break
for i in range(10):
sleep(1)
print('Test')
print('Worker done')
break
Everything works if I change the while to a for loop, but because in this point in my business logic I doesn't have anything to loop for I need to check somehow different the state of the self.stopped(). Is there any way to check it in the while loop?
Or how can I achive this? I tried to use process instead of thread but it wasnt worked because of an error 'process can't pickle tkinter'.
Thank you for any help
This loop will run forever until you set the flag:
def run(self):
while not self.stopped():
sleep(1)
print('Test')
You don't actually need an event. A simple Boolean will do.
FOLLOWUP
Here's an example based on your code that shows how this works:
import threading
from time import sleep
class StoppableThread(threading.Thread):
def __init__(self, caller=None):
super(StoppableThread, self).__init__()
self._stop_event = False
self.caller = caller
def stop(self):
self._stop_event = True
def stopped(self):
return self._stop_event
def run(self) -> None:
while not self.stopped():
sleep(1)
print('Test')
print("exited")
thread = StoppableThread(caller=None)
thread.start()
sleep(5)
thread.stop()
sleep(1)
print("program ending")
In my application I have two threads. Main one and "thread". therad generates some data and stores it in a python list. The main thread periodically copies the content of the list generated by "thread". Both threads have an infinite while loop. My goal is stopping both threads when I press any key+enter. To achieve this goal, the program must wait for a keyboard input while the threads are running. I thought I need another thread (lets say manager) which is only waiting for a keyboard input during execution. Here is what I tried first:
class managerThread(threading.Thread):
is_running = True
def __init__(self):
threading.Thread.__init__(self)
signal.signal(signal.SIGINT, self.kill_all)
signal.signal(signal.SIGTERM, self.kill_all)
def run(self):
input("Press any key+enter to stop: ")
self.is_running = False
def kill_all(self,signum, frame):
print("Process ended with keyboard interrupt")
self.is_running = False
sys.exit(-1)
class thread(threading.Thread):
mgr = managerThread()
mgr.start()
def __init__(self):
threading.Thread.__init__(self)
def run(self):
while (self.mgr.is_running):
print("this is acquiring data")
sleep(2.5)
self.mgr.join()
print("manager stopped")
if __name__ == "__main__":
thread = thread()
thread.start()
while (thread.mgr.is_running):
print("this is copying data")
sleep(3)
thread.join()
print("thread is stopped")
sys.exit(0)
Above code is doing exactly what I want to do. Bu this does not seem correct. The manager manages all the others but it is created in one of the slave threads. Another problem is one may try to create multiple managers in different threads. This is something must be strictly avoided. Then I thought the manager must be inherited by the managed classes. Here is what I tried:
class managerThread(threading.Thread):
is_running = True
def __init__(self):
threading.Thread.__init__(self)
signal.signal(signal.SIGINT, self.kill_all)
signal.signal(signal.SIGTERM, self.kill_all)
self.start()
def run(self):
input("Press any key+enter to stop: ")
self.is_running = False
def kill_all(self,signum, frame):
print("Process ended with keyboard interrupt")
self.is_running = False
sys.exit(-1)
class thread(managerThread):
def __init__(self):
super().__init__()
threading.Thread.__init__(self)
def run(self):
while (self.is_running):
print("this is acquiring data")
sleep(2.5)
print("manager stopped")
if __name__ == "__main__":
thread = thread()
thread.start()
while (thread.is_running):
print("this is copying data")
sleep(3)
thread.join()
print("thread is stopped")
sys.exit(0)
As seen in the second code the major part is the same. I tried to make thread as a child of managerThread. However this is not working. The manager never executes "run" method. So I cannot stop the other threads. Another crucial problem is I do not how to stop super() with join(). I am sure I am doing a mistake about class inheritance but I could not resolve the problem since I do not have too much experience with OOP and threads doubled my confusion.
Note: I do not care about synchronization of the threads.
My questions are:
- Is creating a manager thread correct to safely stop the slave threads? If not, what is the proper way?
- Why the second code is not working? What do I have to modify to get it work?
- Why the parent class is initializing but it is never running "run" method?
- I believe that the parent class is never starting but how can I stop it in the second code if it is actually starting?
Thank you.
Even I did not want to use a global variable to stop safely all the threads I could not find a solution without a global running flag. I also tried to pass a mutable variable to the manager thread but I was unsuccessful. Here is a working sketch that explains how I solved my problem. I hope this helps someone else. Meanwhile, I would be happy if someone propose a better solution :).
Note: I did not debug it.
import sys
import threading, queue
import signal
from time import sleep
import numpy as np
global_running = False
class managerThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
signal.signal(signal.SIGINT, self.kill_all)
signal.signal(signal.SIGTERM, self.kill_all)
def run(self):
global is_running
is_running = True
input("Press any key+enter to stop: ")
is_running = False
print("manager finished")
def kill_all(self,signum, frame):
global is_running
is_running = False
print("Process ended with keyboard interrupt")
sys.exit(-1)
class thread(threading.Thread):
__mgr = managerThread()
__mgr.start()
running = True
def __init__(self):
threading.Thread.__init__(self)
self.myvar = 0
self.queue = queue.Queue()
def currentVar(self):
var = np.empty(1)
while (var.size<=1):
var = self.queue.get()
self.queue.task_done()
return var
def run(self):
global is_running
while (is_running):
print("this is acquiring data")
sleep(2.5)
self.myvar = np.empty(5)
self.queue.put(self.myvar)
self.running = False
self.__mgr.join()
print("manager stopped")
if __name__ == "__main__":
thread = thread()
thread.start()
while (thread.running):
# var = thread.queue.get()
var = thread.currentVar()
print ("value is: ", var)
# thread.queue.task_done()
thread.join()
print("thread is stopped")
sys.exit(0)
I want to create a thread class in python3. I want to control an infinite loop in one of the class function. I want to start or stop this loop in my main function outside the class. suppose this code:
import threading
from time import sleep
class my_thread(threading.Thread):
"""Thread class with a stop() method. The thread itself has to check
regularly for the stopped() condition."""
def __init__(self):
super(my_thread, self).__init__()
self._stop_event = threading.Event()
def stop(self):
print("stopping the thread")
self._stop_event.set()
def stopped(self):
return(self._stop_event.is_set())
def run(self):
print("running the thread")
print("start function startt()")
self._stop_event.clear()
self.startt()
def startt(self):
print("it is going to wait forever")
while not self.stopped():
#wait forever, this part is going to run again and again
pass
print("This line never executes")
if __name__+'__main__':
thr=my_thread()
thr.start()
sleep(5)
print("stopping the thread")
thr.stop()
# I cant start the thread and relative while loop again
#thr.start()
print("Exiting the whole program")
But the problem is I can't start the thread twice, so what I want is to have two function for start and stop my while loop. I dont need to stop the thread but I need to control it. It means I want to call stop() and startt() functions for many times whenever needed in my main routine.
Thanks
first, use Queue in my_thread class for manage task( method ) that complete or called by your thread
you can use LIFO Queue , Prioritry Queue ,FIFO Queue detail
second, add a class-method so you can add new method or task into the queue
add below code into your code :
from queue import Queue
# or
# from multiprocessing import Queue
class my_thread(threading.Thread):
queue = Queue()
#classmethod
def add_task(cls,callable_task):
cls.queue.put(callable_task)
def startt(self):
print("it is going to wait forever")
while not self.stopped():
#wait forever, this part is going to run again and again
if not self.queue.empty():
_m = self.queue.get()
# do what ever you want to do with _m
print("This line never executes")
for stop thread
Class my_thread(Threading.Thread)
stop_event = threading.Event()
#classmethod
def stop_thread(cls)
cls.stop_event.set()
def startt(self):
print("it is going to wait forever")
cls = self.__class__
while not cls.stop_event.is_set():
#wait forever, this part is going to run again and again
if not self.queue.empty():
_m = self.queue.get()
# do what ever you want to do with _m
print("This line never executes")
Now call for stop therad
my_thread.stop_thread()
Exapmle
import threading
import time
class my_thread(threading.Thread):
stop_event = threading.Event()
#classmethod
def stop_thread(cls):
cls.stop_event.set()
def run(self):
print("running the thread")
print("start function startt()")
self.__class__.stop_event.clear()
self.startt()
def startt(self):
print("it is going to wait forever")
cls = self.__class__
print cls.stop_event.is_set()
while not cls.stop_event.is_set():
pass
print("This line never executes")
a = my_thread()
a.start()
time.sleep(0.5)
my_thread.stop_thread()
print "\n\n\n"
b = my_thread()
b.start()
time.sleep(0.5)
my_thread.stop_thread()
Is there a way in python to stop a thread? I have a gui with a method which plays 10 second audio files and sends information to GUI window continuously
I am Multithreading because I dont want the GUI to freeze while my files play. I can stop the thread with my current code but takes a while
My code looks something like this :
class MyThread(threading.Thread):
"""Thread class with a stop() method. The thread itself has to check
regularly for the stopped() condition."""
def __init__(self, *args, **kwargs):
super(MyThread, self).__init__(*args, **kwargs)
self._stop = threading.Event()
def stop(self):
self._stop.set()
def stopped(self):
return self._stop.isSet()
class Myplayer:
// GUI CODE
def play_button(self, widget):
self.mythread = MyThread(target=self.practice)
self.mythread.start()
def stop_button(self, widget):
if self.mythead.IsAlive:
self.self.stop()
def mplayer(self):
while not self.mythread.stopped:
gobject.idle_add(self.insert_text, "\nPlaying a new file")
subprocess.call(["timidity", "myfile.mid"])
Assuming you want to interrupt your midi file while it's playing if your thread is stopped, you can stop the thread more quickly by using Popen instead of call, and then waiting in a loop for either the process to finish, or for the stop request to come in:
class MyThread(threading.Thread):
"""Thread class with a stop() method. The thread itself has to check
regularly for the stopped() condition."""
def __init__(self, *args, **kwargs):
super(MyThread, self).__init__(*args, **kwargs)
self._stop = threading.Event()
def stop(self):
self._stop.set()
def stopped(self):
return self._stop.isSet()
def run(self):
while not self.stopped:
gobject.idle_add(self.insert_text, "\nPlaying a new file")
p = subprocess.Popen(["timidity", "myfile.mid"])
while p.poll() is None: # This will loop until the process has exited.
if self.stopped:
# Someone set the stop flag. Kill the process and exit
p.terminate()
p.join()
return
time.sleep(.1) # Sleep briefly so we don't hog CPU cycles
Here's an example. We start a single thread which does all the work. After two seconds, we tell it to die by setting the shared Event flag.
The worker thread generally runs in a loop, doing a little processing, then checking the flag. If it's set, then it exits, otherwise the thread does some more work.
source
import time
from threading import *
class WorkerThread(Thread):
def __init__(self, die_flag, *args, **kw):
super(WorkerThread,self).__init__(*args, **kw)
self.die_flag = die_flag
def run(self):
for num in range(3):
if self.die_flag.is_set():
print "{}: bye".format(
current_thread().name
)
return
print "{}: num={}".format(
current_thread().name, num,
)
time.sleep(1)
flag = Event()
WorkerThread(name='whiskey', die_flag=flag).start()
time.sleep(2)
print '\nTELL WORKERS TO DIE'
flag.set()
print '\nWAITING FOR WORKERS'
for thread in enumerate():
if thread != current_thread():
print thread.name,
thread.join()
print
output
whiskey: num=0
whiskey: num=1
TELL WORKERS TO DIE
WAITING FOR WORKERS
whiskey whiskey: bye
What's the proper way to tell a looping thread to stop looping?
I have a fairly simple program that pings a specified host in a separate threading.Thread class. In this class it sleeps 60 seconds, the runs again until the application quits.
I'd like to implement a 'Stop' button in my wx.Frame to ask the looping thread to stop. It doesn't need to end the thread right away, it can just stop looping once it wakes up.
Here is my threading class (note: I haven't implemented looping yet, but it would likely fall under the run method in PingAssets)
class PingAssets(threading.Thread):
def __init__(self, threadNum, asset, window):
threading.Thread.__init__(self)
self.threadNum = threadNum
self.window = window
self.asset = asset
def run(self):
config = controller.getConfig()
fmt = config['timefmt']
start_time = datetime.now().strftime(fmt)
try:
if onlinecheck.check_status(self.asset):
status = "online"
else:
status = "offline"
except socket.gaierror:
status = "an invalid asset tag."
msg =("{}: {} is {}. \n".format(start_time, self.asset, status))
wx.CallAfter(self.window.Logger, msg)
And in my wxPyhton Frame I have this function called from a Start button:
def CheckAsset(self, asset):
self.count += 1
thread = PingAssets(self.count, asset, self)
self.threads.append(thread)
thread.start()
Threaded stoppable function
Instead of subclassing threading.Thread, one can modify the function to allow
stopping by a flag.
We need an object, accessible to running function, to which we set the flag to stop running.
We can use threading.currentThread() object.
import threading
import time
def doit(arg):
t = threading.currentThread()
while getattr(t, "do_run", True):
print ("working on %s" % arg)
time.sleep(1)
print("Stopping as you wish.")
def main():
t = threading.Thread(target=doit, args=("task",))
t.start()
time.sleep(5)
t.do_run = False
if __name__ == "__main__":
main()
The trick is, that the running thread can have attached additional properties. The solution builds
on assumptions:
the thread has a property "do_run" with default value True
driving parent process can assign to started thread the property "do_run" to False.
Running the code, we get following output:
$ python stopthread.py
working on task
working on task
working on task
working on task
working on task
Stopping as you wish.
Pill to kill - using Event
Other alternative is to use threading.Event as function argument. It is by
default False, but external process can "set it" (to True) and function can
learn about it using wait(timeout) function.
We can wait with zero timeout, but we can also use it as the sleeping timer (used below).
def doit(stop_event, arg):
while not stop_event.wait(1):
print ("working on %s" % arg)
print("Stopping as you wish.")
def main():
pill2kill = threading.Event()
t = threading.Thread(target=doit, args=(pill2kill, "task"))
t.start()
time.sleep(5)
pill2kill.set()
t.join()
Edit: I tried this in Python 3.6. stop_event.wait() blocks the event (and so the while loop) until release. It does not return a boolean value. Using stop_event.is_set() works instead.
Stopping multiple threads with one pill
Advantage of pill to kill is better seen, if we have to stop multiple threads
at once, as one pill will work for all.
The doit will not change at all, only the main handles the threads a bit differently.
def main():
pill2kill = threading.Event()
tasks = ["task ONE", "task TWO", "task THREE"]
def thread_gen(pill2kill, tasks):
for task in tasks:
t = threading.Thread(target=doit, args=(pill2kill, task))
yield t
threads = list(thread_gen(pill2kill, tasks))
for thread in threads:
thread.start()
time.sleep(5)
pill2kill.set()
for thread in threads:
thread.join()
This has been asked before on Stack. See the following links:
Is there any way to kill a Thread in Python?
Stopping a thread after a certain amount of time
Basically you just need to set up the thread with a stop function that sets a sentinel value that the thread will check. In your case, you'll have the something in your loop check the sentinel value to see if it's changed and if it has, the loop can break and the thread can die.
I read the other questions on Stack but I was still a little confused on communicating across classes. Here is how I approached it:
I use a list to hold all my threads in the __init__ method of my wxFrame class: self.threads = []
As recommended in How to stop a looping thread in Python? I use a signal in my thread class which is set to True when initializing the threading class.
class PingAssets(threading.Thread):
def __init__(self, threadNum, asset, window):
threading.Thread.__init__(self)
self.threadNum = threadNum
self.window = window
self.asset = asset
self.signal = True
def run(self):
while self.signal:
do_stuff()
sleep()
and I can stop these threads by iterating over my threads:
def OnStop(self, e):
for t in self.threads:
t.signal = False
I had a different approach. I've sub-classed a Thread class and in the constructor I've created an Event object. Then I've written custom join() method, which first sets this event and then calls a parent's version of itself.
Here is my class, I'm using for serial port communication in wxPython app:
import wx, threading, serial, Events, Queue
class PumpThread(threading.Thread):
def __init__ (self, port, queue, parent):
super(PumpThread, self).__init__()
self.port = port
self.queue = queue
self.parent = parent
self.serial = serial.Serial()
self.serial.port = self.port
self.serial.timeout = 0.5
self.serial.baudrate = 9600
self.serial.parity = 'N'
self.stopRequest = threading.Event()
def run (self):
try:
self.serial.open()
except Exception, ex:
print ("[ERROR]\tUnable to open port {}".format(self.port))
print ("[ERROR]\t{}\n\n{}".format(ex.message, ex.traceback))
self.stopRequest.set()
else:
print ("[INFO]\tListening port {}".format(self.port))
self.serial.write("FLOW?\r")
while not self.stopRequest.isSet():
msg = ''
if not self.queue.empty():
try:
command = self.queue.get()
self.serial.write(command)
except Queue.Empty:
continue
while self.serial.inWaiting():
char = self.serial.read(1)
if '\r' in char and len(msg) > 1:
char = ''
#~ print('[DATA]\t{}'.format(msg))
event = Events.PumpDataEvent(Events.SERIALRX, wx.ID_ANY, msg)
wx.PostEvent(self.parent, event)
msg = ''
break
msg += char
self.serial.close()
def join (self, timeout=None):
self.stopRequest.set()
super(PumpThread, self).join(timeout)
def SetPort (self, serial):
self.serial = serial
def Write (self, msg):
if self.serial.is_open:
self.queue.put(msg)
else:
print("[ERROR]\tPort {} is not open!".format(self.port))
def Stop(self):
if self.isAlive():
self.join()
The Queue is used for sending messages to the port and main loop takes responses back. I've used no serial.readline() method, because of different end-line char, and I have found the usage of io classes to be too much fuss.
Depends on what you run in that thread.
If that's your code, then you can implement a stop condition (see other answers).
However, if what you want is to run someone else's code, then you should fork and start a process. Like this:
import multiprocessing
proc = multiprocessing.Process(target=your_proc_function, args=())
proc.start()
now, whenever you want to stop that process, send it a SIGTERM like this:
proc.terminate()
proc.join()
And it's not slow: fractions of a second.
Enjoy :)
My solution is:
import threading, time
def a():
t = threading.currentThread()
while getattr(t, "do_run", True):
print('Do something')
time.sleep(1)
def getThreadByName(name):
threads = threading.enumerate() #Threads list
for thread in threads:
if thread.name == name:
return thread
threading.Thread(target=a, name='228').start() #Init thread
t = getThreadByName('228') #Get thread by name
time.sleep(5)
t.do_run = False #Signal to stop thread
t.join()
I find it useful to have a class, derived from threading.Thread, to encapsulate my thread functionality. You simply provide your own main loop in an overridden version of run() in this class. Calling start() arranges for the object’s run() method to be invoked in a separate thread.
Inside the main loop, periodically check whether a threading.Event has been set. Such an event is thread-safe.
Inside this class, you have your own join() method that sets the stop event object before calling the join() method of the base class. It can optionally take a time value to pass to the base class's join() method to ensure your thread is terminated in a short amount of time.
import threading
import time
class MyThread(threading.Thread):
def __init__(self, sleep_time=0.1):
self._stop_event = threading.Event()
self._sleep_time = sleep_time
"""call base class constructor"""
super().__init__()
def run(self):
"""main control loop"""
while not self._stop_event.isSet():
#do work
print("hi")
self._stop_event.wait(self._sleep_time)
def join(self, timeout=None):
"""set stop event and join within a given time period"""
self._stop_event.set()
super().join(timeout)
if __name__ == "__main__":
t = MyThread()
t.start()
time.sleep(5)
t.join(1) #wait 1s max
Having a small sleep inside the main loop before checking the threading.Event is less CPU intensive than looping continuously. You can have a default sleep time (e.g. 0.1s), but you can also pass the value in the constructor.
Sometimes you don't have control over the running target. In those cases you can use signal.pthread_kill to send a stop signal.
from signal import pthread_kill, SIGTSTP
from threading import Thread
from itertools import count
from time import sleep
def target():
for num in count():
print(num)
sleep(1)
thread = Thread(target=target)
thread.start()
sleep(5)
pthread_kill(thread.ident, SIGTSTP)
result
0
1
2
3
4
[14]+ Stopped