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?
Related
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()
Im trying to generate data in two threads and get that data in a separate thread that prints the data.
3 threads, 2 threads generate data , 1 thread consumes the data generated.
The Problem: not getting both generated data into the consumer thread
How can I pass data generated in 2 threads and deliver it in the consumer thread?
#from threading import Thread
import concurrent.futures
import time
# A thread that produces data
def producer(out_q):
while True:
# Produce some data
global data
data = data + 2
out_q.put(data)
# Another thread that produces data
def ac(out2_q):
while True:
global x
x = x + 898934567
out2_q.put(data)
# A thread that consumes data
def consumer(in_q):
while True:
# Get BOTH produced data from 2 threads
data = in_q.get()
# Process the data
time.sleep(.4)
print(data, end=' ', flush=True)
x=0
data = 0
q = Queue()
with concurrent.futures.ThreadPoolExecutor() as executor:
t1 = executor.submit(consumer, q)
t2 = executor.submit(producer,q)
t3 = executor.submit(ac, q)```
I recommend to go with threading.Thread in this case. Please see the code below and follow comments. Feel free to ask questions.
from threading import Thread, Event
from queue import Queue
import time
def producer_one(q: Queue, e: Event):
while not e.is_set():
q.put("one")
time.sleep(1)
print("Producer # one stopped")
def producer_two(q: Queue, e: Event):
while not e.is_set():
q.put("two")
time.sleep(2)
print("Producer # two stopped")
def consumer(q: Queue):
while True:
item = q.get()
print(item)
q.task_done() # is used to unblock queue - all tasks were done
time.sleep(2)
# will never be printed ! - since it is daemon thread
print("All work is done by consumer!")
if __name__ == '__main__':
_q = Queue() # "connects" threads
_e = Event() # is used to stop producers from the Main Thread
# create threads block
producer_th1 = Thread(target=producer_one, args=(_q, _e, ))
producer_th2 = Thread(target=producer_two, args=(_q, _e, ))
# daemon means that thread will be stopped when main thread stops
consumer_th = Thread(target=consumer, args=(_q, ), daemon=True)
try:
# starts block:
producer_th1.start()
producer_th2.start()
consumer_th.start()
time.sleep(20)
_e.set() # ask producers to stop
except KeyboardInterrupt:
_e.set() # ask producer threads to stop
print("Asked Producer Threads to stop")
finally:
producer_th1.join() # main thread is block until producer_th1 is not stopped
producer_th2.join() # main thread is block until producer_th2 is not stopped
_q.join() # now wait consumer to finish all tasks from queue
print("Queue is empty and program will be finished soon")
time.sleep(2) # just wait 2 seconds to show that consumer stops with main thread
print("All done!")
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()
I have a code something like this,
import threading
class Mythread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
print('do some processing')
if __name__=='__main__':
while Ture:
val = raw_input('next thread')
t = MyThread()
t.start()
t.join()
The question is how can I carry on with main function without blocking the main because t.join() stop the main until t does not finish?
You should put code in the "code" tag or else it's not really readable.
And you just have to do something like that.
if name == 'main':
#Thread creation
allThreads = []
while True:
val = raw_input('next thread')
newThread = MyThread()
newThread.start()
allThreads.append(newThread)
#You can do something here
#Waiting for all threads to stop
for thread in allThreads:
thread.join()
I am using code as below for multiple thread in python3, I tried Threads in cpu_count() with 2, 3 and 4 times, but I am not sure if all those threads in using, how can I check if there are some queues are never used?
queue = Queue()
for x in range(cpu_count() * 2):
worker = DownloadWorker(queue)
worker.daemon = True
worker.start()
queue.join()
class DownloadWorker(Thread):
def __init__(self, queue):
Thread.__init__(self)
self.queue = queue
def run(self):
while True:
link, download_path = self.queue.get()
download_link(link, download_path)
self.queue.task_done()
def downloadImage(imageServer, imageLocal, queue):
queue.put((imageServer, imageLocal))
if you want to know if all your threads are working, you can just print the thread name every time it starts a task:
from threading import Thread
from queue import Queue
import random
import time
class DownloadWorker(Thread):
def __init__(self, queue):
Thread.__init__(self)
self.queue = queue
def run(self):
while True:
self.queue.get()
print('Thread: {}'.format(self.name))
time.sleep(random.random())
queue = Queue()
for i in range(100):
queue.put('data')
queue.task_done()
for x in range(4):
worker = DownloadWorker(queue)
worker.daemon = True
worker.start()
time.sleep(10)
Queue uses threading.Condition internally to block/release threads that called get() and threading.Condition uses a threading.Lock. From the documentation of threading.Lock:
When more than one thread is blocked in acquire() waiting for the
state to turn to unlocked, only one thread proceeds when a release()
call resets the state to unlocked; which one of the waiting threads
proceeds is not defined, and may vary across implementations.
I hope this answers the question.