也称有限缓冲问题(Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。
模型结构
该问题涉及到操作系统进程管理当中的两个重要概念——同步和互斥。
同步,表现在生产者和消费者需要协同工作,不允许消费者到一个空缓冲区去取产品;也不允许生产者向一个已装满产品且尚未被取走的缓冲区中投放产品。
互斥,表现在生产者与消费者、生产者与生产者、消费者与消费者任何两个成员之间必须互斥地使用缓冲区。当有一个成员进入缓冲区存/取产品时,其他成员将被关在门外排队等候(被阻塞);当完毕时,通知队首成员进入。
由操作系统理论可知,我们需要三个信号量,分别命名full, empty, mutex,来分别代表消费者的可用资源数、生产者的可用资源数、缓冲区是否可用。初值:full=0(消费者无资源可用),empty=n(生产者有n个资源可用,n代表缓冲区大小),mutex=1(缓冲区可用)。
semaphore mutex=1, empty=n, full=0;
item buffer[n] ;
int in=0,out=0;
void producer(){ //生产者进程
do{
producer an item nextp; //产一个产品
…
wait(empty); //empty减1
wait(mutex);//加锁
buffer[in]=nextp;
in=(in+1)% n; //移动生产指针
signal(mutex);//解锁
signal(full); //full增1
}while(TRUE);
}
void consumer(){//消费者进程
do{
wait(full);
wait(mutex);
nextc=buffer[out];
out= (out+1)%n;
signal(mutex);
signal(empty);
consumer the item in nextc;
...
}while(TRUE);
}
固定生产者的生产能力与消费者每一次的消费量都为1也可以将其设置为随机值。
class Consumer(threading.Thread):
def run(self):
#全局变量
global Resources
global UseTime
global ProduceTime
while True:
# resource2 = random.randint(100,1000) #随机产生一个消耗资源量
resource2 = 1
Lock.acquire() #开启线程锁
if resource2 <= Resources:
Resources -= resource2
print("{}消费者目前拥有的资源量为{},使用了{}资源量,还剩余{}资源量".format(threading.current_thread(),Resources+resource2, resource2, Resources))
else:
if UseTime >= ProduceTime: #如果消费者拥有的资源小于消耗的资源,则退出
Lock.release() #释放线程锁
break
print("{}消费者需要使用{}的资源,目前拥有的资源量为{},所以资源不足".format(threading.current_thread(),Resources,resource2))
Lock.release()
time.sleep(0.3)
class Producer(threading.Thread):
def run(self):
#全局变量
global Resources
global UseTime
global ProduceTime
while True:
# resource1 = random.randint(100,1000) #随机产生一个生产的资源量
resource1 = 1
Lock.acquire() #开启线程锁
if UseTime >= ProduceTime:
Lock.release() #释放线程锁
break
UseTime += 1
Resources += resource1 #生产者增加资源
print("%s生产者生产了%d的使用资源,现在总共还有%d的可用资源量"%(threading.current_thread(),resource1,Resources))
Lock.release()
time.sleep(0.3)
import time
import random
import threading
Resources = 0 #初始可用资源量
Lock = threading.Lock() #创建线程锁
ProduceTime = 30 #定义一个生产次数
UseTime = 0 #初始化使用次数
def main():
for i in range(4):
t=Consumer(name='消费者%d'%(i))
t.start()
for x in range(4):
y = Producer(name='生产者%d'%(x))
y.start()
if __name__ == '__main__':
main()