Python locking threads not working in an example - python-3.x

I am trying to grasp the Lock in multithreading module in python. But for some reason it is not locking the objects and lets the next thread run without waiting for the lock to release.
Here is the code:
from threading import Thread, Lock
import time
database_value = 0
def increase(lock):
global database_value
lock.acquire()
local_copy = database_value
local_copy += 1
time.sleep(0.1)
database_value = local_copy
lock.release()
if __name__ == '__main__':
lock = Lock()
print('start value',database_value)
thread1 = Thread(target =increase, args = (lock,))
thread2 = Thread(target =increase, args = (lock,))
print('start')
#start
thread1.start()
thread2.start()
#join
print('join')
thread1.join()
thread1.join()
print('end value', database_value)
The Output I am expecting is:
start value 0
start
join
end value 2
But the Output I get:
start value 0
start
join
end value 1

At the join step, you wait for thread1 instead of thread2.
#join
print('join')
thread1.join()
thread1.join() # Should be thread2
If you change it below, it will work.
#join
print('join')
thread1.join()
thread2.join()

Related

How to stop a specific Thread among others?

I'm using threads for a project which look like this :
thread1 = Thread(target=function, args=('x','y',1,2))
thread2 = Thread(target=function, args=('a','b',1,2))
thread1.start()
thread2.start()
Everything is working but I wanted to add an option to my code. To kill my threads i'm currently using While X==True in my targeted function. So when I want to kill a Thread i have to pass While==False.
The issue is doing that kill all the threads who use this function.
So how can i kill only thread1 without doing the same for thread2 if both were running together and using the same targeted function ?
Thank you !
Below a simplified example of what i'm actually doing
def test_thread(freq):
starttime=time.time()
while RUN==True:
try:
if 1==1:
print('1')
sleep(freq - ((time.time() - starttime) % freq))
except Exception as Ex:
print(Ex)
pass
RUN = True
run_test = Thread(target=test_thread, args=(20))
run_test.start()
You could pass a different, mutable object as an argument to each of the two threads:
class Stopper:
def __init__(self):
self.flag = True
def ok_to_keep_going(self):
return self.flag
def stop_now(self):
self.flag = False
def test_thread(freq, stopper):
...
while stopper.ok_to_keep_going():
...
if __name__ == '__main__':
t1_stopper = Stopper()
t2_stopper = Stopper()
t1 = Thread(target=test_thread, args=(T1_FREQ, t1_stopper))
t2 = Thread(target=test_thread, args=(T2_FREQ, t2_stopper))
t1.start()
t2.start()
Now you can stop thread 1 by calling t1_stopper.stop_now(), or stop thread 2 by calling t2_stopper.stop_now()
Or, for fewer lines of code:
def test_thread(freq, stopper):
...
while stopper[0]:
...
if __name__ == '__main__':
t1_stopper = [True]
t2_stopper = [True]
t1 = Thread(target=test_thread, args=(T1_FREQ, t1_stopper))
t2 = Thread(target=test_thread, args=(T2_FREQ, t2_stopper))
t1.start()
t2.start()
Now you stop thread t1 by setting t1_stopper[0]=False.

using time.sleep() in Thread python3

Im trying to make a simple thread in python3 where the test1 will run until a certain amount of number and then sleep while the test2 will still be running and also when it reaches a certain number it will go to sleep.
My code goes like this:
def test2(count):
if count == 8:
print("sleep for 4 sec")
time.sleep(3.0)
print("test2 thread = {}".format(count))
def test1(count):
if count == 5:
print("sleep for 5 sec")
time.sleep(3.0)
print("test1 thread = {}".format(count))
for num in range(0,10):
t1 = threading.Thread(target=test1, args=(num,))
t2 = threading.Thread(target=test2, args=(num,))
t1.start()
t2.start()
Also, i been coding python before but without using thread and now i wanted to have a go on it and hope this will end well :)
ohh, and additionally the output doesn't matter if they overlap.
The threading.Thread() creates new thread and t1.start() just dispatch it.
This code:
for num in range(0,10):
t1 = threading.Thread(target=test1, args=(num,))
t2 = threading.Thread(target=test2, args=(num,))
t1.start()
t2.start()
actually creates and start 2 new threads per iteration. At the end you have 20 threads + master thread.
Also when you start thread you should wait until it ends or run it as daemon thread. With daemon thread you are saying I don't care what you do and when you end.
Basic thread usage can looks like this:
import threading
def do_stuff():
print("Stuff on thread {}".format(threading.get_ident()))
print("Main thread {}".format(threading.get_ident()))
t = threading.Thread(target=do_stuff) # Specify what should be running in new thread
t.start() # Dispatch thread
t.join() # Wait until the thread is done
Note: threading.get_ident() gives you unique identifier of the thread where this function is called.
Now from you example if you want start 2 independent threads you can do this:
import threading
import time
def test2():
for count in range(0, 10):
if count == 8:
print("test2: sleep for 4 sec")
time.sleep(3.0)
print("test2: thread = {}".format(count))
def test1():
for count in range(0, 10):
if count == 5:
print("test 1: sleep for 5 sec")
time.sleep(3.0)
print("test1: thread = {}".format(count))
t1 = threading.Thread(target=test1)
t2 = threading.Thread(target=test2)
t1.start()
t2.start()
t1.join()
t2.join()
But you might want to synchronize those threads and send them some item at the "same" time.
import threading
# Create threads
t1 = threading.Thread(target=test1)
t2 = threading.Thread(target=test2)
# Run threads
t1.start()
t2.start()
# Go through some list or whatever
for num in range(0,10):
# send num to t1
# send num to t2
# wait for t1 and t2
pass
# Wait until threads are finished with their jobs
t1.join()
t2.join()
For sending value to other thread we can user queue.Queue. You can safely put there value in one thread and second thread can read it or wait until there is something (or multiple thread can write and multiple thread can read).
import threading
import time
import queue
def test2(q):
while True:
count = q.get() # Get data from the q2 queue
if count == 8:
print("test2: sleep for 4 sec")
time.sleep(3.0)
print("test2: thread = {}".format(count))
def test1(q):
while True:
count = q.get() # Get data from the q1 queue
if count == 5:
print("test 1: sleep for 5 sec")
time.sleep(3.0)
print("test1: thread = {}".format(count))
# Creates queues
q1 = queue.Queue()
q2 = queue.Queue()
# Create threads
t1 = threading.Thread(target=test1, args=(q1, ))
t2 = threading.Thread(target=test2, args=(q2, ))
# Run threads
t1.start()
t2.start()
# Go through some list or whatever
for num in range(0, 10):
# send num to t1
q1.put(num)
# send num to t2
q2.put(num)
# wait for t1 and t2
# ???
# Wait until threads are finished with their jobs
t1.join()
t2.join()
Oh wait... how can we know that threads are done with their work and we can send another value? Well we can use Queue again. Create new pair and sending e.g. True at the end of the test? function and then wait read in main loop from those queues. But for sending state information we should use threading.Event.
import threading
import time
import queue
def test2(q, e):
while True:
count = q.get() # Get data from the q2 queue
if count == 8:
print("test2: sleep for 4 sec")
time.sleep(3.0)
print("test2: thread = {}".format(count))
e.set() # Inform master the processing of given value is done
def test1(q, e):
while True:
count = q.get() # Get data from the q1 queue
if count == 5:
print("test 1: sleep for 5 sec")
time.sleep(3.0)
print("test1: thread = {}".format(count))
e.set() # Inform master the processing of given value is done
# Creates queues
q1 = queue.Queue()
q2 = queue.Queue()
# Create events
e1 = threading.Event()
e2 = threading.Event()
# Create threads
t1 = threading.Thread(target=test1, args=(q1, e1))
t2 = threading.Thread(target=test2, args=(q2, e2))
# Run threads
t1.start()
t2.start()
# Go through some list or whatever
for num in range(0, 10):
# send num to t1
q1.put(num)
# send num to t2
q2.put(num)
# wait for t1
e1.wait()
# wait for t2
e2.wait()
# Wait until threads are finished with their jobs
t1.join()
t2.join()
Now we are almost there but the script never ends. It's because the test? functions (threads) waits in infinite loop for data (from queues q1/q2). We need some way how to tell them "Ok, that's all folks". For that we can say None value in queues means end. The result following:
import threading
import time
import queue
def test2(q, e):
while True:
count = q.get() # Get data from the q2 queue
if count is None: # Exit on None value
return
if count == 8:
print("test2: sleep for 4 sec")
time.sleep(3.0)
print("test2: thread = {}".format(count))
e.set() # Inform master the processing of given value is done
def test1(q, e):
while True:
count = q.get() # Get data from the q1 queue
if count is None: # Exit on None value
return
if count == 5:
print("test 1: sleep for 5 sec")
time.sleep(3.0)
print("test1: thread = {}".format(count))
e.set() # Inform master the processing of given value is done
# Creates queues
q1 = queue.Queue()
q2 = queue.Queue()
# Create events
e1 = threading.Event()
e2 = threading.Event()
# Create threads
t1 = threading.Thread(target=test1, args=(q1, e1))
t2 = threading.Thread(target=test2, args=(q2, e2))
# Run threads
t1.start()
t2.start()
# Go through some list or whatever
for num in range(0, 10):
# send num to t1
q1.put(num)
# send num to t2
q2.put(num)
# wait for t1
e1.wait()
# wait for t2
e2.wait()
# Inform threads to exit
q1.put(None)
q2.put(None)
# Wait until threads are finished with their jobs
t1.join()
t2.join()
Note: instead of using parameters in threads "main" functions you can use global variables, because global variables or class attributes are shared across all threads. But usually it is bad practice.
Be aware of gotchas coming with threading, for example exception handling is not so easy. Imagine that function test1 raises exception before calling e.set(). Then the master thread never ends waiting on e1.wait().
Also CPython (the most common implementation of the Python) has something called GIL, which basically (with some exceptions) allows running only 1 thread at a time and the others are sleeping.
Threading documentation
Queue documentation

Kill all threads python

Starting my script off with:
for i in range(threads):
t = Thread(target=getSizes, args=(i,))
t.start()
Then when one of the threads is able to get the variables needed for the other functions it does:
for i in range(threads):
t = Thread(target=cart, args=(i, sizes, prod_name, product_id))
t.start()
Is there any way to till all threads started on getSizes() and then start new threads on cart()?
If your worker function does work in a loop, it can use a common resource like an Event to signal when work is complete and it should return. Here is an example
import threading
import time
import random
def getSizes(done_event):
while not done_event.is_set():
print("get size")
if random.randint(0, 20) == 10:
print("got size")
done_event.set()
do_cart()
else:
time.sleep(random.random())
print("sizes done")
def do_getSizes():
event = threading.Event()
threads = []
for i in range(5):
t = threading.Thread(target=getSizes, args=(event,))
t.start()
threads.append(t)
for t in threads:
t.join()
def cart():
print("I haz the cartz")
def do_cart():
time.sleep(1)
threads = []
for i in range(5):
t = threading.Thread(target=cart)
t.start()
threads.append(t)
for t in threads:
t.join()
do_getSizes()

How to stop a Thread - Python 3

Hi guys, I am struggling trying to stop a thread, I don't get any error but my thread don't stop. I would appreciate some help. I have a button who call my function lev which should stop the thread when I turned my button off. Follow the part of the code below:
exitFlag = 0
def levt():
print("Executando")
while ((app.frames[Acionamento].var.get()==2) and exitFlag==0):
print("o thread")
t1fvm = time.time() #Tempo final luminĂ¡ria esquerda
n1mv = (t1fvm-t1ivm)*0.6
global levm
levm = levm+n1mv
print(levm)
def lev():
app.frames[Acionamento].esquerdaFrame.vendasFrame.luminaria_esquerdaFramev.label6["text"] = "LuminĂ¡ria A"
global exitFlag
global thread2
thread2 = Thread(target=levt)
if GPIO.input(17):
GPIO.output(17, GPIO.LOW)
app.frames[Acionamento].esquerdaFrame.vendasFrame.luminaria_esquerdaFramev.lev_button["text"]="Desligado"
if thread2.isAlive():
exitFlag = 1
else:
global t1ivm
t1ivm = time.time()
GPIO.output(17, GPIO.HIGH)
app.frames[Acionamento].esquerdaFrame.vendasFrame.luminaria_esquerdaFramev.lev_button["text"]="Ligado"
thread2.start()
Since thread2 is always initiated with new thread inside lev(), so if thread2.isAlive() will be always evaluated as False and exitFlag will never be set to 1. Therefore the running thread will never be stopped.
Move thread2 = Thread(target=levt) to line before thread2.start():
def lev():
...
#thread2 = Thread(target=levt) # moved to line before thread2.start()
if GPIO.input(17):
...
else:
...
thread2 = Thread(target=levt)
thread2.start()

Mutex with queue ordered threads

I have a list of threads. The following code releases the mutex lock at the end of the block using the 'with' statement. This is very useful as it allows the user to cycle through each thread and choose to stop it or keep it running.
import threading
#subclass with state
class Mythread(threading.Thread):
def __init__(self,myId, astr, mutex):
self.myId = myId
self.astr = astr
self.mutex = mutex
threading.Thread.__init__(self)
def run(self):
while True:
with self.mutex:
print('[%s] => %s' % (self.myId, self.astr))
ans=raw_input("Enter s to stop thread...")
if ans == 's':
break
stdoutmutex = threading.Lock()
threads = []
for i,j in zip(range(7),['A', 'B', 'C','D','E','F','G']):
thread = Mythread(i,j,stdoutmutex)
thread.start()
threads.append(thread)
for thread in threads:
thread.join()
To ensure the threads are cycled through in the order as found in the 'threads' list, I've used the Queue module to control the order of the thread locks:
thread = q.get()
with thread.mutex:
The modified script:
import threading, Queue
#subclass with state
class Mythread(threading.Thread):
def __init__(self,myId, astr, mutex):
self.myId = myId
self.astr = astr
self.mutex = mutex
threading.Thread.__init__(self)
def run(self):
while True:
thread = q.get()
with thread.mutex:
print('[%s] => %s' % (self.myId, self.astr))
ans=raw_input("Enter s to stop thread...")
if ans == 's':
q.task_done()
break
else:
q.put(thread)
stdoutmutex = threading.Lock()
threads = []
q = Queue.Queue()
for i,j in zip(range(7),['A', 'B', 'C','D','E','F','G']):
thread = Mythread(i,j,stdoutmutex)
threads.append(thread)
for thread in threads:
q.put(thread)
thread.start()
for thread in threads:
thread.join()
This appears to work as the correct thread order A,B,C... is sent to the standard output. However, can it be verified that the Queue is working and it isn't just a coincidence?

Resources