线程等待与唤醒机制

44 阅读2分钟

在多线程编程中,线程之间经常需要进行通信和协作。为了实现线程之间的通信和协作,Python提供了内置的条件变量(condition)对象。条件变量是一种同步工具,它允许线程等待某个条件的满足,并在条件满足时被唤醒。

在下面的代码示例中,有一个消费者线程和两个生产者线程。消费者线程不断地从队列中消费项目,而生产者线程不断地向队列中生产项目。为了防止消费者线程在队列为空时无限期地等待,我们使用了条件变量来让消费者线程在队列为空时等待,并在生产者线程生产项目时被唤醒。

import threading
import time
import queue

class ItemQueue:
    def __init__(self):
        self.items = queue.Queue()
        self.condition = threading.Condition()

    def consume(self):
        self.condition.acquire()
        while self.items.empty():
            self.condition.wait()
        item = self.items.get()
        self.condition.release()
        print(threading.currentThread(), "Consumed One Item")

    def produce(self):
        self.condition.acquire()
        self.items.put(1)
        self.condition.notifyAll()
        self.condition.release()
        print(threading.currentThread(), "Produced One Item")

def consumer(itemq):
    while True:
        time.sleep(1)
        itemq.consume()

def producer(itemq):
    while True:
        time.sleep(1)
        itemq.produce()

if __name__ == "__main__":
    itemq = ItemQueue()

    consumer_1 = threading.Thread(target=consumer, args=(itemq,))
    consumer_1.start()

    consumer_2 = threading.Thread(target=consumer, args=(itemq,))
    consumer_2.start()

    producer_1 = threading.Thread(target=producer, args=(itemq,))
    producer_1.start()

    producer_2 = threading.Thread(target=producer, args=(itemq,))
    producer_2.start()

2、解决方案

为了解决这个问题,我们需要修改消费者线程的代码,使消费者线程在队列为空时等待条件变量的通知,并在条件变量被唤醒时继续执行从队列中消费项目的操作。

import threading
import time
import queue

class ItemQueue:
    def __init__(self):
        self.items = queue.Queue()
        self.condition = threading.Condition()

    def consume(self):
        self.condition.acquire()
        while self.items.empty():
            self.condition.wait()
        item = self.items.get()
        self.condition.release()
        print(threading.currentThread(), "Consumed One Item")

    def produce(self):
        self.condition.acquire()
        self.items.put(1)
        self.condition.notifyAll()
        self.condition.release()
        print(threading.currentThread(), "Produced One Item")

def consumer(itemq):
    while True:
        time.sleep(1)
        itemq.consume()

def producer(itemq):
    while True:
        time.sleep(1)
        itemq.produce()

if __name__ == "__main__":
    itemq = ItemQueue()

    consumer_1 = threading.Thread(target=consumer, args=(itemq,))
    consumer_1.start()

    consumer_2 = threading.Thread(target=consumer, args=(itemq,))
    consumer_2.start()

    producer_1 = threading.Thread(target=producer, args=(itemq,))
    producer_1.start()

    producer_2 = threading.Thread(target=producer, args=(itemq,))
    producer_2.start()

在修改后的代码中,消费者线程在从队列中消费项目之前,会先检查队列是否为空。如果队列为空,消费者线程就会调用条件变量的wait方法等待条件变量的通知。当生产者线程向队列中生产项目时,它会调用条件变量的notifyAll方法唤醒所有正在等待的消费者线程。这样,消费者线程就可以继续执行从队列中消费项目的操作了。