How to ensure there is no runaway thread - python

import threading
from playsound import playsound
import time
soundList = []
bot_run = True
class myThread (threading.Thread):
def __init__(self):
global soundList
threading.Thread.__init__(self)
def run(self):
global soundList
global bot_run
while bot_run:
try:
time.sleep(1)
playsound(soundList.pop(0))
except:
pass
def main():
global soundList
global bot_run
input()
soundThread = myThread()
soundThread.start()
while not ((user_input := input('sound name: ')) == 'close'):
soundList.append(user_input)
bot_run = False
main()
I want to ensure someone who clicks the x on cmd doesn't end the program but the thread keeps going.
Does the thread die on its own when the main program ends? Does the bot_run variable cease to exist and therefore exit the while loop? How can I make sure I don't have this loop running forever when it's no longer being used if the user exited the program without following procedure?

Related

Why is helper thread not exiting in this python script?

I have three files:
helper.py
from globalvariables import *
global exit_signal
global exited_signal
def helperstart():
global exited_signal
while True:
if exit_signal is True:
exited_signal = True
print ('Exiting from helper thread')
return
main.py
from globalvariables import *
import threading
import helper
global exit_signal
global exited_signal
def mainstart():
global exit_signal
helper_thread = threading.Thread(target = helper.helperstart)
input ('Press <enter> to start the thread')
helper_thread.start()
input ('Press <enter> to end the thread')
exit_signal = True
# check if helper has exited
if exited_signal is True:
print ('Helper exited successfully')
if __name__ == '__main__':
mainstart()
globalvariables.py
exit_signal = False
exited_signal = False
From main.py, the value of exit_signal should be edited to True. This should make the helper thread exit. But it is not exiting. I've tried printing the value of exit_signal from helperstart() function and it keeps showing as False. So, the main.py isn't editing the variable properly. Please help me figure out why.

Why the thread does not stops?

The thread started in the start_thread method does not stop. Why ?
import time
import threading
cont_running = True
def start_thread():
threading.Thread(target=run).start()
def stop_thread():
cont_running = False
def run():
while cont_running:
print 'Thread running : ' + str(cont_running)
time.sleep(0.2)
print 'Thread ended'
start_thread()
time.sleep(2)
stop_thread()
In stop_thread(), your assignment statement creates a local variable named cont_running. This local variable is unrelated to the global variable of the same name.
Try this:
def stop_thread():
global cont_running
cont_running = False

How to continuously flash LED (or other while loop) while Python code continues to run

I would like to be able to flash an LED continuously while my main while loop continues. I understand that in the following code when the function led_flash() gets called, the script will stop until the while loop defined in the function ends. This prohibits the remainder of the code from running.
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
GPIO.setup(25, GPIO.OUT)
def led_flash():
while TRUE:
GPIO.output(25, ON)
time.sleep(1)
GPIO.output(25, OFF)
time.sleep(1)
while True:
if x=1
led_flash()
...do other stuff
I have read that threading will work in this instance, however I have not found an example simple enough for me to grasp. Additionally, if threading, how would I be able to end the led_flash() function thread later in my main while loop?
Based on answers from here and here you can start a thread like this:
import threading
while True:
if x = 1:
flashing_thread = threading.Thread(target=led_flash)
flashing_thread.start()
#continue doing stuff
Since, in your case, you want to stop the thread (I assume if x doesn't equal 1), then you can create a thread stopping class like so:
import threading
import sys
class StopThread(StopIteration): pass
threading.SystemExit = SystemExit, StopThread
class Thread2(threading.Thread):
def stop(self):
self.__stop = True
def _bootstrap(self):
if threading._trace_hook is not None:
raise ValueError('Cannot run thread with tracing!')
self.__stop = False
sys.settrace(self.__trace)
super()._bootstrap()
def __trace(self, frame, event, arg):
if self.__stop:
raise StopThread()
return self.__trace
And call it like: flashing_thread.stop()
Put it all together to get:
import threading
import sys
import RPi.GPIO as GPIO
import time
class StopThread(StopIteration): pass
threading.SystemExit = SystemExit, StopThread
class Thread2(threading.Thread):
def stop(self):
self.__stop = True
def _bootstrap(self):
if threading._trace_hook is not None:
raise ValueError('Cannot run thread with tracing!')
self.__stop = False
sys.settrace(self.__trace)
super()._bootstrap()
def __trace(self, frame, event, arg):
if self.__stop:
raise StopThread()
return self.__trace
#############################################################
GPIO.setmode(GPIO.BCM)
GPIO.setup(25, GPIO.OUT)
def led_flash():
while TRUE:
GPIO.output(25, ON)
time.sleep(1)
GPIO.output(25, OFF)
time.sleep(1)
# x gets defined somewhere
while True:
if x == 1:
flashing_thread = Thread2(target=led_flash)
flashing_thread.start()
#continue doing stuff
else:
if flashing_thread and flashing_thread.isAlive():
flashing_thread.stop()
A simple example after looking at the documentation:
from threading import Thread
import time
def main_loop():
mythread = LedThread()
mythread.start()
time.sleep(20) # execute while loop for 20 seconds
mythread.stop()
class LedThread(Thread):
def __init__(self):
super(LedThread, self).__init__()
self._keepgoing = True
def run(self):
while (self._keepgoing):
print 'Blink'
time.sleep(0.5)
def stop(self):
self._keepgoing = False
main_loop()
Ideally, you should be using the target parameter from threading.Thread.__init__, because it allows you to push your function into the thread. Ryan Schuster's example is the more robust of the two, though I hope this one can help you understand what threads are by using only the basics necessary to run one.

Python send variables to thread

I'm trying to create my own threading class in Python2.7. I want it to be able to stop that thread with my own class function. Currently I have something like this:
class loop(threading.Thread):
def __init__(self, myvar):
super(loop, self).__init__()
self.terminate = False
self.myvar = myvar
def run(self):
while not self.terminate:
do.smthng.useful(self.myvar)
def change(self, newvar):
self.myvar = newvar #Doesnt work, in run() my old var is still being used
def stoploop(self):
self.terminate = True #Also not working
l = loop(1)
l.start()
time.sleep(1)
l.change(2) #thread still using "1"
time.sleep(1)
l.stoploop() #doesnt stop
I've read some posts here about this, but it wasnt what I needed.
Any help would be appreciated.
Thank you.
EDIT:
As some of the commenters already stated, this part of code looks like to be really working! Problem is in another place of my project. I've found it, but can't solve it. Maybe some of you could help.
So, my project uses Apache Thrift library and the server is in python.
Server.py:
loo = loop(0)
handler = ServHandler(loo)
processor = serv.Processor(handler)
transport = TSocket.TServerSocket('0.0.0.0', port=9090)
tfactory = TTransport.TBufferedTransportFactory()
pfactory = TBinaryProtocol.TBinaryProtocolFactory()
server = TProcessPoolServer.TProcessPoolServer(processor, transport, tfactory, pfactory)
print 'Starting the server...'
server.serve()
ServHandler.py:
class ServHandler:
def __init__(self, loo):
self.loo = loo
def terminate(self): #Function that can be called remotely
self.loo.stoploop() #Doesn't work
In above case thread isn't terminated and I don't why. There's no error, object exists, but it sets self.terminate value somewhere else. The object id seems to be the same as well as memory address, but it just looks like object is different although loop init function is called only once...
Below is the example, when the loop is terminated successfully.
ServHandler.py:
class ServHandler:
def __init__(self, loo):
self.loo = None
def terminate(self): #Function that can be called remotely
self.loo.stoploop() #Does work!!!!!!
def create(self):
self.loo = loop(0) #Function that can be called remotely
When I create loop object remotely, I can terminate it remotely. But it doesn't fit me. There should be a thread created before thrift server is served and multiple users have to be able to change vars/terminate/etc of that thread. How can I achieve this?
Thank you!
Not a answer per sae, but a useful debug code for the OP
from time import sleep
from threading import Thread
class loop(Thread):
def __init__(self, myvar):
Thread.__init__(self)
self.terminate = False
self.myvar = myvar
def run(self):
while self.terminate is False:
print('Run says myvar is:',self.myvar)
sleep(0.5)
def change(self, newvar):
self.myvar = newvar
def stoploop(self):
self.terminate = True
l = loop(1)
l.start()
sleep(1)
l.change(2)
sleep(1)
l.stoploop()
print('Final product:',l.myvar)
sleep(2)
print('Is the thread alive:',l.isAlive())
Tried your code with some debugging prints, and it's working?
Following code produced:
[torxed#archie ~]$ python test.py
Run says myvar is: 1
Run says myvar is: 1
Run says myvar is: 2 <-- Proves that change() does change `myvar`
Run says myvar is: 2
Final product: 2 <-- Also the global scope knows about the change
Is the thread alive: False <-- And the thread got terminated as intended
However, these are not bulletproof ideas when fetching data or dealing with thread-returns for a number of reasons (even tho i use this method myself from time to time), you should consider using thread.join which should be used in combination with l.toplooop() like so:
l = loop(1)
l.start()
l.change(2)
l.stoploop()
ret = l.join()
Also when updating data you should aquire locks on your data so collisions don't occur, have a look at semaphore objects.
Is it what you need?
import threading
import time
class Worker(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.state = threading.Condition()
self.variable = 10
self.paused = False
def run(self):
while True:
with self.state:
if self.paused:
self.state.wait()
self.do_stuff()
def do_stuff(self):
time.sleep(.1)
print self.variable
def resume(self):
with self.state:
self.paused = False
self.state.notify()
def pause(self):
with self.state:
self.paused = True
loop = Worker()
loop.start()
time.sleep(1)
loop.pause()
loop.variable = 11
print 'CHANGED!'
loop.resume()
time.sleep(1)

multi threads modify a global list in python

i want to add an item into a global list every 2 seconds in one thread,
and save the list into database before empty it every 3 seconds in another thread.
i create two local varibles to monitor the total added items and total saveditems, they should be equal every 6 senconds,but it is not.
here is my code:
import datetime
import psutil,os,time
from threading import *
class AddToList(Thread):
totalAdded=0
def run(self):
lock=RLock()
lock.acquire()
while True:
entryList.append("AddToList at "+str(datetime.datetime.now()))
self.totalAdded=self.totalAdded+len(entryList)
print("totalAdded:"+str(self.totalAdded))
time.sleep(2)
lock.release()
class SaveList(Thread):
totalSaved=0
'''save entry to server'''
def __init__(self):
Thread.__init__(self)
def run(self):
lock=RLock()
lock.acquire()
while True:
#save list to database,then empty the list
self.totalSaved=self.totalSaved+len(entryList)
del entryList[:]
print("totalSaved:"+str(self.totalSaved))
time.sleep(3)
lock.release()
if __name__=="__main__":
global entryList
entryList=[]
addClass= AddToList()
addClass.start()
saveClass=SaveList()
saveClass.start()
result:
totalAdded:2
totalSaved:2
totalAdded:3
totalSaved:3totalAdded:4
totalAdded:6
totalSaved:5
totalAdded:7
totalSaved:6
totalAdded:8
totalAdded:10
totalSaved:8
totalAdded:11
totalSaved:9
totalAdded:12
totalAdded:14
totalSaved:11
totalAdded:15
totalSaved:12
...........
...........
totalAdded:51
totalSaved:39totalAdded:52
totalAdded:54
totalSaved:41
totalAdded:55
totalSaved:42
totalAdded:56
totalAdded:58
totalSaved:44
totalAdded:59
totalSaved:45totalAdded:60
......
......
i anm new to python and searched a lot about threading ,Lock and RLock ,but with no luck.
where am wrong?
To make Lock and RLock work you must use the same object in every thread. The lock objects must have the same "visibility" of the object that you want to "protect".
Here is a new version of you code which should work. It also avoid using things like global variables etc.
import datetime
import time
import threading
class AddToList(threading.Thread):
def __init__(self, lock, entryList):
threading.Thread.__init__(self)
self.totalAdded = 0
self.entryList = entryList
self.lock = lock
def run(self):
while True:
self.lock.acquire()
entryList.append("AddToList at {}".format(datetime.datetime.now()))
self.totalAdded += 1
self.lock.release()
print("totalAdded: {}".format(self.totalAdded))
time.sleep(2)
class SaveList(threading.Thread):
def __init__(self, lock, entryList):
threading.Thread.__init__(self)
self.totalSaved = 0
self.entryList = entryList
self.lock = lock
def run(self):
while True:
self.lock.acquire()
self.totalSaved += len(self.entryList)
del self.entryList[:]
self.lock.release()
print("totalSaved: {}".format(self.totalSaved))
time.sleep(3)
if __name__=="__main__":
lock=threading.Lock()
entryList=[]
addClass = AddToList(lock, entryList)
addClass.start()
saveClass = SaveList(lock, entryList)
saveClass.start()
Some things to note:
Use Lock instead of RLock when you don't have any particular needs. RLock is much slower.
As already pointed out by someone it is better avoid using global variables when not needed. Also Class variables should be used only when it makes sense.
When you use a lock you should try to limit as much as possible the code between acquire and release. In you previous code you never release the lock.

Categories