5
\$\begingroup\$

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()

\$\endgroup\$

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.