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")
Related
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()
I have a class Controller with a method job which I'd like to run at regular intervals using the schedule module. Further, I'd like to have several 'variations' of this job running on separate threads such that they are all can be gracefully interrupted using Cntrl+C. (I do not want to make the threads daemon threads and shut them down abruptly).
Here is what I have so far:
import schedule
import threading
import time
import signal
import sys
class Controller(object):
def __init__(self, name="controller", interval=1):
self.name = name
self.interval = interval
def job(self):
print("My name is {}.".format(self.name))
class ThreadController(threading.Thread):
def __init__(self, *args, **kwargs):
super(ThreadController, self).__init__()
self.controller = Controller(*args, **kwargs)
self._stop = threading.Event()
def stop(self):
self._stop.set()
def stopped(self):
return self._stop.isSet()
def run(self):
schedule.every(self.controller.interval).seconds.do(self.controller.job)
while not self.stopped():
schedule.run_pending()
if __name__ == "__main__":
controller1 = ThreadController(name="foo")
controller2 = ThreadController(name="bar")
try:
controller1.start()
controller2.start()
time.sleep(1000) # This ensures that the execution remains within the 'try' block (for a significant amount of time)
except KeyboardInterrupt:
controller1.stop()
controller2.stop()
The program works, in that for the first 1000 seconds it will alternately print My name is foo. and My name is bar. until Cntrl+C is pressed.
To make the code remain within the try block, however, I am for the time being using time.sleep which is not an elegant solution. What I actually want is to 'wait' until Cntrl+C is pressed. Is there an elegant way to implement this?
(Another thing I tried is the following, after Capture keyboardinterrupt in Python without try-except:
if __name__ == "__main__":
controller1 = ThreadController(name="foo")
controller2 = ThreadController(name="bar")
def signal_handler(signal, frame):
print("Stopping threads and exiting...")
controller1.stop()
controller2.stop()
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
controller1.start()
controller2.start()
but this seems not to work, as the program keeps printing after Cntrl+C is pressed).
Ctrl+C terminates you main thread and controller1 and controller2 are still running.
You may demonize them
controller1.daemon = True
controller2.daemon = True
before starting. But when you main thread starts these two it will exit and shut down them as well.
So in order to keep it busy run a infinite loop in it
while True:
sleep(0.1)
For the time being I'm going with an infinite loop like the one suggested by Alexey Smirnov. The implementation is slightly different and uses Python's signal:
import schedule
import threading
import time
import signal
import sys
class Controller(object):
def __init__(self, name="controller", interval=1):
self.name = name
self.interval = interval
def job(self):
print("My name is {}.".format(self.name))
class ThreadController(threading.Thread):
def __init__(self, *args, **kwargs):
super(ThreadController, self).__init__()
self.controller = Controller(*args, **kwargs)
self._stop = threading.Event()
def stop(self):
self._stop.set()
def stopped(self):
return self._stop.isSet()
def run(self):
schedule.every(self.controller.interval).seconds.do(self.controller.job)
while not self.stopped():
schedule.run_pending()
def signal_handler(signum, frame):
controller_threads = [thread for thread in threading.enumerate() if isinstance(thread, ThreadController)]
for controller_thread in controller_threads:
print("Stopping {}.".format(controller_thread))
controller_thread.stop()
sys.exit(1)
if __name__ == "__main__":
controller1 = ThreadController(name="foo")
controller2 = ThreadController(name="bar")
signal.signal(signal.SIGINT, signal_handler)
controller1.start()
controller2.start()
while True: time.sleep(0.1) # Keep the main thread alive until interrupted
The advantage of not using daemon threads is that they are not abruptly, but gracefully shut down.
I am new to python programming. I am trying to make a GUI with stoppable threads.
I borrowed some code from
https://stackoverflow.com/a/325528
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()
I have function which creates a thread for another function in another class that runs an infinite loop.
class MyClass :
def clicked_practice(self):
self.practicethread = MyThread(target=self.infinite_loop_method)
self.practicethread.start()
def infinite_loop_method()
while True :
// Do something
#This doesn't seem to work and I am still stuck in the loop
def infinite_stop(self)
if self.practicethread.isAlive():
self.practicethread.stop()
I want to create a method to stop this thread .
What's happening here?
I think you missed the 'The thread itself has to check regularly for the stopped() condition' bit of that documentation.
Your thread needs to run like this:
while not self.stopped():
# do stuff
rather than while true. Note that it is still only going to exit at the 'start' of a loop, when it checks the condition. If whatever is in that loop is long-running, that may cause unexpected delays.
import threading
import time
class MultiThreading:
def __init__(self):
self.thread = None
self.started = True
def threaded_program(self):
while self.started:
print("running")
# time.sleep(10)
def run(self):
self.thread = threading.Thread(target=self.threaded_program, args=())
self.thread.start()
def stop(self):
self.started = False
self.thread.join()
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