I have implemented a producer/consumer functionality using threads in a given framework and
I'm pretty sure I did not cover all possible scenarios.
I made a small reproducible version. Lines ending with #
simulate the functionality of the framework.
In the original code the total number of products and consumers is not known until the end.
My goal is to wait in the producer thread until the consumer thread has finished the current product and vice versa. So the order should be:
- consumer boot (first or 2nd step)
- producer produce product #1 (first or 2nd step)
- consumer consume product #1
- producer produce product #2
- consumer consume product #2
...
until there is either no product or consumer left
This is a MRE of my code (with sleeps as placeholders), alter the value of n
to simulate more or less consumers:
import threading
import time
products = [1,2,3,4,5,None] #
prodcnt = 0 #
n = 5 #
def produce():
#simulating incremental calculation of product
while True: #
global prodcnt #
product = products[prodcnt] #
prodcnt += 1 #
print(" Producer: init product "+str(product))
if product == None: #
global exhausted
exhausted = True
getProdEvent.set()
print(" Producer: exhausted")
return
elif noConsumers:
print(" Producer: no consumers left")
return
else:
print(" Producer: waiting for permission to process "+str(product))
getConsumeEvent.wait()
print(" Producer: Permission granted "+str(product))
time.sleep(0.01)
print(" Producer: finished producing "+str(product))
getProdEvent.set()
getConsumeEvent.clear()
exhausted = False
noConsumers = False
step = 0
getProdEvent = threading.Event()
getConsumeEvent = threading.Event()
x = threading.Thread(target=produce) #
x.start() #
while not exhausted and not noConsumers:
if step > 0:
print("Consumer: wait for product #" +str(step)+"\n", end="")
getProdEvent.clear()
if not exhausted:
getProdEvent.wait()
else:
print("Consumer: booting ... please wait")
time.sleep(0.02)
print("Consumer: finishing #"+str(step))
time.sleep(0.05)
getConsumeEvent.set()
if step >= n: # simulate no Consumers left
print("Consumer: No consumers left")
noConsumers = True
getConsumeEvent.set()
step +=1
Is there a more straight forward way to force them to wait for each other? Also I feel like my code could break easily.
The producer uses the value of step
so the command step +=1
should run only if the producer is stuck in the line getConsumeEvent.wait()