在循环中在python中锁定变量

时间:2014-12-29 15:49:06

标签: python multithreading producer-consumer

我正在尝试在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()

我的代码是否一遍又一遍地锁定多个实例?我问的原因是我是线程新手并且在队列满了之后,生产者停止创建任何进程(在我的情况下是客户)

2 个答案:

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