Radu Stoenescu
Radu Stoenescu

Reputation: 3205

Producers - consumers in python

For the producer-consumer problem I have come up with this solution:

import threading
import random
import time

class Bucket:

def __init__(self, size):
    self.size = size
    self.current_size = 0
    self.cond_var = threading.Condition()

def available_for_put(self):
    return self.current_size < self.size

def available_for_get(self):
    return self.current_size > 0

def put(self):
    self.current_size = self.current_size + 1
    print(self)
    self.cond_var.notify_all()

def get(self):
    self.current_size = self.current_size - 1
    print(self)
    self.cond_var.notify_all()

def acquire(self):
    self.cond_var.acquire()

def release(self):
    self.cond_var.release()

def wait(self):
    self.cond_var.wait()

def __str__(self):
    return "Size is {0}".format(self.current_size)

class Worker(threading.Thread):


PRODUCER = 1
CONSUMER = 0

def __init__(self, bucket, kind):
    threading.Thread.__init__(self)
    self.kind = kind
    self.bucket = bucket

def run(self):
    while(1):
        self.bucket.acquire()
        while(((self.kind == Worker.PRODUCER) and (not self.bucket.available_for_put())) or \
            ((self.kind == Worker.CONSUMER) and (not self.bucket.available_for_get()))):
            self.bucket.wait()
            ### self.bucket.acquire()
        if self.kind == Worker.PRODUCER:
            self.bucket.put()
        else:
            self.bucket.get()
        time.sleep(0.1)
        self.bucket.release()


bucket = Bucket(10)
workers = []

for i in range(10):
    workers.append(Worker(bucket, i % 2))

for w in workers:
    w.start()
    print("Thread started")

for w in workers:
    w.join()

Apparently if I remove the while(1) loop and make every thread run the block inside the loop only once it reaches a deadlock and I can't understand why.

Upvotes: 1

Views: 4078

Answers (2)

gavinb
gavinb

Reputation: 20018

The Producer-Consumer pattern can be readily implemented using Python's built in Queue support:

This could simplify your code. Also very useful is the scheduler:

And since your question is tagged with Python-3.x, you should definitely have a look at the concurrent.futures module:

Your workers could be tasks and the bucket could become a queue.

Upvotes: 3

Radu Stoenescu
Radu Stoenescu

Reputation: 3205

Apparently the problem is that after waking up from wait you reacquire the lock and thus the now commented out acquire will block.

Upvotes: 0

Related Questions