我正在尝试在Python中实现Producer使用者场景... 如果队列已满,生产者应该停止锁定变量,如果它不满,则释放它...我在循环中使用锁定变量
def run(self):
#mutexProducer.acquire()
#Entering Critical section
#print self.queue.qsize()
while True:
customer=Customer()
self.mutex.acquire()# acquire condition variable to see if queue is full
if self.queue.full():
print "Queue is full : Cant Enter Critical Section"
#print "Customer %d is discarded" %(customer.id)
elif not self.queue.full() :
print "i am here"
print self.mutex.release()
self.mutex.acquire()
#Critical Section
self.queue.put(customer)#pushing Customer to queue
print "Customer %d Enters the Queue with %d service " %(customer.id,customer.serviceTime)
#critical Section
self.mutex.release()
我的代码是否一遍又一遍地锁定多个实例?我问的原因是我是线程新手并且在队列满了之后,生产者停止创建任何进程(在我的情况下是客户)
答案 0 :(得分:1)
我在你的代码中添加了一些注释,这有一些问题:
def run(self):
while True:
customer=Customer()
self.mutex.acquire()
if self.queue.full():
print "Queue is full : Cant Enter Critical Section"
# NOTE 1: you have to release mutex here: self.mutex.release()
elif not self.queue.full():
# NOTE 2: other threads can enter after releasing the lock
print self.mutex.release()
self.mutex.acquire()
#Critical Section
self.queue.put(customer)
print "Customer %d Enters the Queue with %d service " %(
customer.id,customer.serviceTime
)
self.mutex.release()
替代注1 (但动机相同):
def run(self):
while True:
customer=Customer()
self.mutex.acquire()
if self.queue.full():
print "Queue is full : Cant Enter Critical Section"
elif not self.queue.full():
# NOTE 2: other threads can enter after releasing the lock
print self.mutex.release()
self.mutex.acquire()
#Critical Section
self.queue.put(customer)
print "Customer %d Enters the Queue with %d service " %(
customer.id,customer.serviceTime
)
# Note 1 alternative - release mutex (cancel 'if' branching effect)
self.mutex.release()
我实际上不理解它的逻辑。释放锁定允许线程检查队列,而其他线程则推送到队列,但是你发现队列不是线程安全的。
如果你使用队列的线程安全性,那么为什么要使用互斥开始?
编辑:主要问题是,如您所指定的那样,您将与制作人一起获取互斥锁两次。您只能获取一次互斥锁(至少如果它是threading.Lock
个对象)。在您的interperter中尝试此代码:
>>> import threading
>>> lock = threading.Lock()
>>> lock.acquire()
True
>>> lock.acquire()
看看会发生什么。
无论哪种方式,找出关键部分的逻辑。固定代码(注1)应防止由于未在第一个if分支上释放互斥锁而遇到的阻塞。
祝你好运。答案 1 :(得分:1)
使用Lock
的最佳方法是使用with语句。它会自动处理锁的获取和释放,即使该块以异常退出也是如此。
例如:
lock = threading.Lock()
with lock:
print "the lock is locked for the duration of this block"
try:
with lock:
raise Exception("block exits with an exception")
except Exception:
pass
assert not lock.locked()
如果不进行新的小修改,就不可能将with语句替换为代码。但是,这通常反映了应该如何使用锁。
def run(self):
while True:
customer=Customer()
# enter critical section
with self.mutex:
queue_full = self.queue.full()
# exit critical section
if queue_full:
print "Queue is full : Cant Enter Critical Section"
else:
print "i am here"
# enter critical section
with self.mutex:
#pushing Customer to queue
self.queue.put(customer)
# exit critical section
print "Customer %d Enters the Queue with %d service " % \
(customer.id, customer.serviceTime)
但是,因为你有多个相关的关键部分,如果有多个生产者线程,就会出现问题。如果一个线程检查队列的状态,退出其关键部分,暂停以支持另一个线程,并且在恢复执行时队列已满,则会发生什么。在早期关键部分检查的条件不再适用。因此,所有相关的动作必须在同一个关键部分中一起完成。如果只有一个生产者,那么这不会是一个问题。
应对多个生产者:
def run(self):
while True:
customer=Customer()
if not self.add_customer(customer):
print "Queue is full: failed to add customer"
def add_customer(self):
with self.mutex:
# entire section that checks if the queue is full and then adding the
# customer is considered critical
if not self.queue.full():
self.queue.put(customer)
return True # customer added
return False # customer not added
在您的一条评论中查看了here提供的代码。我可以看到你没有正确使用锁。每个协调线程必须能够访问同一个锁,而不是为每个线程创建一个新的单独锁。
您的主要方法应该类似于:
def main():
queue_size=2
queue=Queue.Queue(maxsize=queue_size)
print queue.full()
# scrap the following three lines
mutexProducer=threading.Lock()#mutex variablaes
mutexConsumer=thread.allocate_lock()
mutexTeller=thread.allocate_lock()
mutex = threading.Lock()
# producer and scheduler use the same lock
producer = Producer(queue, mutex)
scheduler = Scheduler(queue, mutex)
producer.start()
scheduler.start()