面试题答案
一键面试关键代码片段(以Python为例)
import threading
# 创建锁和条件变量
lock = threading.Lock()
condition = threading.Condition(lock)
# 共享资源,例如一个队列
queue = []
MAX_SIZE = 5
# 生产者线程函数
def producer(id):
global queue
while True:
with lock:
while len(queue) >= MAX_SIZE:
# 队列已满,生产者等待
condition.wait()
item = id * 10 + len(queue)
queue.append(item)
print(f"Producer {id} produced {item}")
# 唤醒消费者
condition.notify()
# 消费者线程函数
def consumer(id):
global queue
while True:
with lock:
while len(queue) == 0:
# 队列已空,消费者等待
condition.wait()
item = queue.pop(0)
print(f"Consumer {id} consumed {item}")
# 唤醒生产者
condition.notify()
# 创建生产者和消费者线程
producer_thread1 = threading.Thread(target=producer, args=(1,))
consumer_thread1 = threading.Thread(target=consumer, args=(1,))
# 启动线程
producer_thread1.start()
consumer_thread1.start()
# 等待线程结束(这里实际上不会结束,因为是无限循环)
producer_thread1.join()
consumer_thread1.join()
条件变量的等待和唤醒机制在该模型中的作用
- 等待机制:
- 生产者:当共享队列已满(
len(queue) >= MAX_SIZE
)时,生产者调用condition.wait()
。此时,生产者线程会释放它持有的锁(这里是lock
),并进入等待状态。这样其他线程(如消费者线程)就有机会获取锁并操作共享队列。 - 消费者:当共享队列已空(
len(queue) == 0
)时,消费者调用condition.wait()
。消费者线程同样会释放锁并进入等待状态,以便其他线程(如生产者线程)能够获取锁并向队列中添加数据。
- 生产者:当共享队列已满(
- 唤醒机制:
- 生产者:当生产者向队列中添加了数据后,调用
condition.notify()
。这会唤醒一个等待在条件变量上的线程(可能是消费者线程)。被唤醒的线程会尝试重新获取锁,一旦获取到锁,就可以继续执行(例如消费者开始消费数据)。 - 消费者:当消费者从队列中取出数据后,也调用
condition.notify()
。这会唤醒一个等待在条件变量上的线程(可能是生产者线程),使得生产者可以继续向队列中添加数据。
- 生产者:当生产者向队列中添加了数据后,调用
通过条件变量的等待和唤醒机制,生产者 - 消费者模型可以有效地实现线程间的同步,避免了资源竞争和死锁等问题,保证了共享资源(队列)的正确使用。