首页 > 解决方案 > Concurrent access to a shared resource using conditions in Threads Python

问题描述

I have the below sample pretty basic code for working with conditions in Python:

import threading
import random
import time

class Producer(threading.Thread):
    """
    Produces random integers to a list
    """

    def __init__(self, integers, condition):
        """
        Constructor.

        @param integers list of integers
        @param condition condition synchronization object
        """
        threading.Thread.__init__(self)
        self.integers = integers
        self.condition = condition

    def run(self):
        """
        Thread run method. Append random integers to the integers list
        at random time.
        """
        while True:
            integer = random.randint(0, 256)
            self.condition.acquire()
            print 'condition acquired by %s' % self.name
            self.integers.append(integer) 
            print '%d appended to list by %s' % (integer, self.name)
            print 'condition notified by %s' % self.name
            self.condition.notify()
            print 'condition released by %s' % self.name
            self.condition.release()
            time.sleep(1)

class Consumer(threading.Thread):
    """
    Consumes random integers from a list
    """

    def __init__(self, integers, condition):
        """
        Constructor.

        @param integers list of integers
        @param condition condition synchronization object
        """
        threading.Thread.__init__(self)
        self.integers = integers
        self.condition = condition

    def run(self):
        """
        Thread run method. Consumes integers from list
        """
        while True:
            self.condition.acquire()
            print 'condition acquired by %s' % self.name
            while True:
                if self.integers:
                    integer = self.integers.pop()
                    print '%d popped from list by %s' % (integer, self.name)
                    break
                print 'condition wait by %s' % self.name
                self.condition.wait()
            print 'condition released by %s' % self.name
            self.condition.release()

def main():
    integers = []
    condition = threading.Condition()
    t1 = Producer(integers, condition)
    t2 = Consumer(integers, condition)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

if __name__ == '__main__':
    main()

As per my understanding when the consumer calls the wait() method it would release the condition and go into sleep.

When the producer notifies the threads after it calls notify() it seems that neither of the consumers are reacquiring the condition before they try to pop from the integer list.

Is this not a race condition ?

标签: pythonmultithreading

解决方案


消费者在被唤醒后不需要重新获取条件,wait()因为他们直到恢复后才释放它wait()
他们释放的是始终与条件相关联的锁,无论是显式还是隐式。
文档

条件变量总是与某种锁相关联;这可以传入或默认创建一个。[...]锁是条件对象的一部分:您不必单独跟踪它。

通过获取/释放条件以及调用wait()resp 来隐式获取和释放锁。从中醒来。

acquire() 和 release() 方法也调用关联锁的相应方法。
[..]
wait() 方法释放锁,然后阻塞,直到另一个线程通过调用 notify() 或 notify_all() 唤醒它。一旦唤醒,wait() 重新获取锁并返回。

所以总是最多有一个线程可以持有锁,从而在任何给定的时间点安全地修改共享资源。


推荐阅读