Stopping a thread once condition matches - python

I want to trigger upfunction and stop when it writes 3 in the filename. Basically I want to stop a thread once the condition is met as shown below.
def getstatus():
fh = open(filename,'r')
return fh.read()
def upfunction(arg):
for i in range(arg):
print ("backup running")
print(getstatus())
target = open(filename, 'w')
target.write(str(i))
sleep(1)
if __name__ == "__main__":
thread = Thread(target = upfunction, args = (10, ))
thread.start()
print(getstatus())
while getstatus() != "3":
print("NOT 3 ")
sleep(0.5)
continue
thread.stop()
print("thread finished...exiting")
It shows
AttributeError: 'Thread' object has no attribute 'stop'
Please see me as newbie to python.
Any help will be highly appreciated

'Thread' object has no attribute 'stop' is helpful answer from python interpretator to you
You should place thread termination condition to upfunction.
def upfunction(arg):
i = 0
while getstatus() != "3":
print ("backup running")
print(getstatus())
target = open(filename, 'w')
target.write(str(i))
i += 1
sleep(1)
if __name__ == "__main__":
thread = Thread(target = upfunction, args = (10, ))
thread.start()
print(getstatus())
print("thread finished...exiting")

you can just use threading deamon method to kill this new thread.
thread.start()
thread.deamon()
when the main threads ends this custom threads also dies .so there is no need of that.

Here are some explanation about the right way to do that: Is there any way to kill a Thread in Python?.
And as Lex said [0], you can add a condition (in upfunction arguments) to stop your target function.

Related

Python: Change class member in a thread

I am currently trying to change member variables of a class via a separate thread. I want to access the changed variables from the main process, but it seems that a copy is always created that is no longer visible to the main thread. Do you have any ideas here?
Many thanks in advance for your help.
Example code:
class foo():
def __init__(self):
self.data = 0
def test_f(self):
for it in range(0,3):
self.data = self.data + 1
time.sleep(1.0)
print('thread terminated')
print(self.data)
#This function is outside the class; Unfortunately, indentations do not work properly here right now
def run(m_foo):
for it in range(0,10):
m_foo.test_f(q)
time.sleep(1.0)
if __name__ == '__main__':
m_foo = foo()
p = Process(target=run, args=(m_foo))
p.start()
stop_char = ""
while stop_char.lower() != "q":
stop_char = input("Enter 'q' to quit\n")
print("Process data:")
print(foo.data)
if p.is_alive():
p.terminate()
Output:
Process data:
0
....
thread terminated
21
thread terminated
24
thread terminated
27
thread terminated
30
...
Process data:
0
The class multiprocessing.Process does not create a thread. It creates a completely new processing with its own memory space.
Use threading.Thread instead:
https://docs.python.org/3/library/threading.html#threading.Thread

communication between two multiprocessing in real time

I have 2 processing, I need that when something happened on one process, something else will happen on the other.
For example:
import multiprocessing
def function_1(num):
while True:
status = False
for i in range (num):
if i == 100:
status = True
i +=1
def function_2():
while True:
if status == True:
print("status changed")
if __name__ == '__main__':
num = 101
a = multiprocessing.Process(target=function_1,args=(num,))
b = multiprocessing.Process(target=function_2)
a.start()
b.start()
a.join()
b.join()
This code obviously does not work, how can I make it work? I don't need one process to end and then get the result, I need the process to continue after that... is there a way to do that?
thank you!
Instead of a using a shared variable, for the purpose of making function_2 wait until function_1 reaches a certain state, you can create a multiprocessing.Queue instance to pass to both functions, and take advantage of the fact that Queue.get blocks until the queue receives something to dequeue, and make function_1 put something into the queue once it reaches the desired state:
import multiprocessing
def function_1(queue, num):
while True:
for i in range(num):
print(i)
if i == 3:
queue.put(None)
def function_2(queue):
queue.get()
print('do something')
if __name__ == '__main__':
num = 5
queue = multiprocessing.Queue()
a = multiprocessing.Process(target=function_1, args=(queue, num))
b = multiprocessing.Process(target=function_2, args=(queue,))
a.start()
b.start()
You forgot to add .join() after the start().
Try this :
a.start()
b.start()
a.join()
b.join()

What is the correct way to control threads?

I need run 3 or 5 threads approx, this threads monitoring some activities in the OS. Because of this, the main program must be running in background. I've read many examples and explanations, but I'm not clear yet how to launch threads and main program in the background and after that, how to control them.
I start threads in daemon mode from main program:
import threading
import time
def fun1():
while True:
print("Thread 1")
time.sleep(1)
def fun2():
while True:
print("Thread 2")
time.sleep(1)
def fun3():
while True:
print("Thread 3")
time.sleep(1)
def main():
thread1 = threading.Thread(target=fun1)
thread1.daemon = True
thread1.start()
thread2 = threading.Thread(target=fun2)
thread2.daemon = True
thread2.start()
thread3 = threading.Thread(target=fun3)
thread3.daemon = True
thread3.start()
if __name__ == '__main__':
try:
main()
while True:
print("------------")
print("Main program")
print("------------")
time.sleep(3)
except (KeyboardInterrupt, SystemExit):
print("Terminated")
and after that I run the main program in background with (I'm not sure that this is the best way to do it for what I want to achieve):
python daemon_thread.py &
How control the threads after main program initialization if I need stop a specific thread, change its state, or whatever? How to access a specific thread or the main program?
I understand now how to do, to resume the problem: I have a main program running in background and this main program have some threads. But I want with another script or program stop the main program with the threads safetly and in some cases pause and resume threads.
I didn't have a correctly concept about how to use the Threads. I can stop or send signal to this threads from main program How?,with a database or config file.
I updated my project with this changes:
import threading
import time
import sqlite3
def fun1(stop_event1):
while not stop_event1.is_set():
print("Thread 1")
time.sleep(1)
def fun2(stop_event2):
while not stop_event2.is_set():
print("Thread 2")
time.sleep(1)
def fun3(stop_event3):
while not stop_event3.is_set():
print("Thread 3")
time.sleep(1)
def main():
stop_event1 = threading.Event()
thread1 = threading.Thread(target=fun1, args=(stop_event1,))
thread1.daemon = True
thread1.start()
stop_event2 = threading.Event()
thread2 = threading.Thread(target=fun2, args=(stop_event2,))
thread2.daemon = True
thread2.start()
stop_event3 = threading.Event()
thread3 = threading.Thread(target=fun3, args=(stop_event3,))
thread3.daemon = True
thread3.start()
while True:
print("------------")
print("Main program")
print("------------")
time.sleep(3)
if alive_main():
print("Finish Threads")
stop_event1.set()
stop_event2.set()
stop_event3.set()
print("Bye")
break
def alive_main():
conn = sqlite3.connect('example.db')
c = conn.cursor()
c.execute('SELECT alive_main FROM config')
row = c.fetchone()
if row[0] == 1:
return True
else:
return False
if __name__ == '__main__':
try:
main()
except (KeyboardInterrupt, SystemExit):
print("Terminated")
If I want change with another class or script the state of my threads, I just change config table in my database y this take effect in the Threads, from main function. In this example if I stop correctly my threads and program just I update table, that's it.
sqlite> UPDATE config SET alive_main = 1;
I need read about Signals and Condition Objects to complement correctly Threads uses.
Thanks everyone!

Communicate data between threads in python

I am new to python I have very little knowledge about threads in python. Here is my sample code.
import threading
from threading import Thread
import time
check = False
def func1():
print ("funn1 started")
while check:
print ("got permission")
def func2():
global check
print ("func2 started")
time.sleep(2)
check = True
time.sleep(2)
check = False
if __name__ == '__main__':
Thread(target = func1).start()
Thread(target = func2).start()
What I want is to see see "got permission" as the output. But with my current code it is not happening. I assume that the func1 thread is closed before func2 changes the check value to True.
How can I keep func1 alive?
I have researched on the internet but I could not found a solution.
Any help would be appreciated.
Thank you in advance!
The problem here is that func1 performs the check in the while loop, finds it is false, and terminates. So the first thread finishes without printing "got permission".
I don't think this mechanism is quite what you are looking for. I would opt to use a Condition like this,
import threading
from threading import Thread
import time
check = threading.Condition()
def func1():
print ("funn1 started")
check.acquire()
check.wait()
print ("got permission")
print ("funn1 finished")
def func2():
print ("func2 started")
check.acquire()
time.sleep(2)
check.notify()
check.release()
time.sleep(2)
print ("func2 finished")
if __name__ == '__main__':
Thread(target = func1).start()
Thread(target = func2).start()
Here the condition variable is using a mutex internally to communicate between the threads; So only one thread can acquire the condition variable at a time. The first function acquires the condition variable and then releases it but registers that it is going to wait until it receives a notification via the condition variable. The second thread can then acquire the condition variable and, when it has done what it needs to do, it notifies the waiting thread that it can continue.
from threading import Thread
import time
check = False
def func1():
print ("funn1 started")
while True:
if check:
print ("got permission")
break
def func2():
global check
print ("func2 started")
time.sleep(2)
check = True
time.sleep(2)
check = False
if __name__ == '__main__':
Thread(target = func1).start()
Thread(target = func2).start()
func1 must be like this
def func1():
print("func1 started")
while True:
if check:
print("got permission")
break
else:
time.sleep(0.1)

Controlling a python thread with a function

Thanks to those who helped me figure out I needed to use threading to run a loop in a control script I have run, I now have an issue to try and control the thread - by starting or stopping it based on a function:
I want to start a process to get a motor to cycle through a movement based on a 'start' parameter sent to the controlling function, also I want to send a 'stop' parameter to stop the thread too - here's where I got to:
def looper():
while True:
print 'forward loop'
bck.ChangeDutyCycle(10)
fwd.ChangeDutyCycle(0)
time.sleep(5)
print 'backwards loop'
bck.ChangeDutyCycle(0)
fwd.ChangeDutyCycle(20)
time.sleep(5)
def looper_control(state):
t = threading.Thread(target=looper)
if state == 'start':
t.start()
elif state == 'stop':
t.join()
print 'looper stopped!!'
This starts the thread okay when I call looper_control('start') but throws an error when looper_control('stop'):
File "/usr/lib/python2.7/threading.py", line 657, in join
raise RuntimeError("cannot join thread before it is started")
RuntimeError: cannot join thread before it is started
EDIT: looper_control called from here
if "motor" in tmp:
if tmp[-1:] == '0':
#stop both pin
MotorControl('fwd',0,0)
print 'stop motors'
looper_control('stop')
elif tmp[-1:] == '2':
#loop the motor
print 'loop motors'
looper_control('start')
UPDATE: Ive not been able to stop the thread using the method suggested - I thought I had it!
here's where I am:
class sliderControl(threading.Thread):
def __init__(self,stop_event):
super(sliderControl,self).__init__()
self.stop_event = stop_event
def run(self):
while self.stop_event:
print 'forward loop'
bck.ChangeDutyCycle(10)
fwd.ChangeDutyCycle(0)
time.sleep(5)
print 'backwards loop'
bck.ChangeDutyCycle(0)
fwd.ChangeDutyCycle(20)
time.sleep(5)
def looper_control(state,stop_event):
if state == 'start':
t = sliderControl(stop_event=stop_event)
t.start()
elif state == 'stop':
#time.sleep(3)
stop_event.set()
#t.join()
print 'looper stopped!!'
called via:
if tmp[-1:] == '0':
#stop both pin
MotorControl('fwd',0,0)
print 'stop motors'
#stop_thread_event = threading.Event()
print 'stopping thread'
print stop_thread_event
looper_control('stop',stop_thread_event)
elif tmp[-1:] == '2':
#loop the motor
print 'loop motors'
global stop_thread_event
stop_thread_event = threading.Event()
print stop_thread_event
looper_control('start', stop_thread_event)
It looked like a separate thread event was being called by loop and stop, so I thought a global would sort it out but its just not playing ball. When I start the loop - it runs, but when I try to stop it, I get looper stopped!! , but the process just keeps running
Your top-level thread routine will need to become an event handler that listens to a Queue object (as in from Queue import Queue) for messages, then handles them based on state. One of those messages can be a shutdown command, in which case the worker thread function simply exits, allowing the main thread to join it.
Instead of time.sleep, use threading.Timer with the body of the timer sending a message into your event queue.
This is a substantial refactoring. But especially if you plan on adding more conditions, you'll need it. One alternative is to use a package that handles this kind of thing for you, maybe pykka.
To stop a python thread you can use threading.Event()
try this:
class YourClass(threading.Thread):
def __init__(self, stop_event):
super(YourClass, self).__init__()
self.stop_event = stop_event
def run(self):
while not self.stop_event.is_set():
# do what you need here (what you had in looper)
def looper_control(state, stop_event):
if state == 'start':
t = YourClass(stop_event=stop_event)
t.start()
elif state == 'stop':
stop_event.set()
and call to looper_control:
stop_thread_event = threading.Event()
looper_control(state, stop_thread_event)
you only can "start" once a thread
but you can lock and unlock the thread.
the best way to stop and start a thread is with mutex, Example:
#!/usr/bin/python
import threading
from time import sleep
mutex2 = threading.Lock()
#This thread add values to d[]
class Hilo(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
while True:
mutex2.acquire()
#Add values to d[]
d.append("hi from Peru")
mutex2.release()
sleep(1)
d=[];
hilos = [Hilo()]
#Stop Thread
#If you have more threads you need make a mutex for every thread
mutex2.acquire()
#Start treades, but the thread is lock
for h in hilos:
h.start()
#so you need do
#unlock THREAD<
mutex2.release()
#>START THREAD
#Sleep for 4 seconds
sleep(4)
#And print d[]
print d
print "------------------------------------------"
#WAIT 5 SECONDS AND STOP THE THREAD
sleep(5)
try:
mutex2.acquire()
except Exception, e:
mutex2.release()
mutex2.acquire()
#AND PRINT d[]
print d
#AND NOW YOUR TRHEAD IS STOP#
#When the thread is lock(stop), you only need call: mutex2.release() for unlock(start)
#When your thread is unlock(start) and you want lock(stop):
#try:
# mutex2.acquire()
#except Exception, e:
# mutex2.release()
# mutex2.acquire()

Categories