【一】生产者和消费者实现原理:
简易思维导图
1.问题背景:避免进程之间出现临界资源的互斥访问的死锁现象
2.解决方式:记录型信号量机制
3.具体细节:
- mutex:互斥信号量,初始值是1
- empty:判空信号量
- full:判满信号量
- array[n]:缓冲池存放产品
4.实现好处: 解决死锁
【二】实现细节设计:
- 缓存池:循环队列 in,out标记队头和队尾
利用in,out指针实现加减操作放入拿出产品
in:指向当前最后产品的存储空间(队位,放入)(rear)
out:指向最早放入产品存储空间(队头,拿取)(head)
具体生产者:生产者生产产品,in=(in+1)%n记录更新位置
具体消费者:消费者拿取产品,out=(out+1)%n记录更新位置 - 互斥信号量:初始值为1,保证临界资源的互斥性
3.代码构建:
对象 消费者和生产者 调用
循环队列 (阻塞队列)缓冲池
4.代码实现:
①基本队列内容编写
class Queue(object):# 定义队列类
def __init__(self,size):
self.size = size #定义队列长度
self.queue = []#存储队列 列表
#返回对象的字符串表达式 方便调试
def __str__(self):
return str(self.queue)#什么含义
#初始化队列
#def init(self):
#入队
def inQueue(self,n):
if self.isFull():
return -1
self.queue.append(n)#列表末尾添加新的对象
#出队
def outQueue(self):
if self.isEmpty():
return -1
firstElement = self.queue[0] #删除队头元素
self.queue.remove(firstElement) #删除队操作
return firstElement
#删除某元素
def delete(self,n,m):
self.queue[n] = m
#插入某元素
def inPut(self,n,m):#n代表列表当前的第n位元素 m代表传入的值
self.queue[n] = m
#获取当前长度
def getSize(self):
return len(self.queue)
#判空
def isEmpty(self):
if len(self.queue)==0:
return True
return False
#判满
def isFull(self):
if len(self.queue) == self.size:
return True
return False
#if __name__ == '__main__':#如何使用?
queueTest = Queue(10)
for i in range(10):
queueTest.inQueue(i)
print('列表元素',queueTest)
print('列表长度',queueTest.getSize())
print('判空',queueTest.isEmpty())
print('判满',queueTest.isFull())
queueTest.inPut(1,20)#list【0】 = 2
queueTest.outQueue()#出队
print('当前列表',queueTest)
结果:
列表元素 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
列表长度 10
判空 False
判满 True
当前列表 [20, 2, 3, 4, 5, 6, 7, 8, 9]
②生产者消费者代码具体实现
#全局变量实现头尾指针动态指向内容i
i = 0
head = 0
rear = 0
mutex = 1#互斥信号量 初始为1标志当前队列有无被占用
flag =1 #标志初始化
#消费者
class Customer():
def __init__(self):
print('>>>消费者请求访问仓库')
def opreate(self,customer):
if flag ==1: #如何使队列只能创建一个对象 全局
customer.init()#列表越界很可能就是列表越界
global mutex # 创建队列对象 以便队列操作
if mutex == -1:
return print('>>>缓冲区当前正有人操作,消费者不能操作')
else:
mutex = mutex - 1
if (customer.isEmpty())== True:
print('>>>当前缓冲区为空,消费者不能取用产品')
if input('是否调用生产者提供补给(输入1-YES|0-NO) ')=='1':
print('>>>调用生产者')
mutex = mutex+1
product=Producer()
product.opreate(customer)
else:
mutex = mutex + 1
return print('>>>拒绝提醒,消费者继续等待')
else:
customer.outPut() #其中包含head的操作
print('消费者取用产品完毕,当前产品队列从', head, '到', rear, '处依然存有产品','缓存队列',customer)
mutex =mutex+1 #操作完毕互斥量恢复
class Producer():
def __init__(self):
print('>>>生产者请求访问缓存区')
def opreate(self,producer):
if flag == 1:
producer.init() #重复初始化 傻瓜式不影响
print(producer)
global mutex
if mutex == -1:
return print('>>>缓冲区当前繁忙,生产者不能进行操作')
else:
mutex = mutex-1
if producer.isFully() == True:
print('>>>缓冲区为满,生产者不能放入产品')
if input('是否调用消费者进行消耗(输入1-YES|0-NO) ') == 1:
print('>>>调用消费者')
mutex = mutex+1
customer=Customer()
customer.operate(CirQueue())
else:
mutex = mutex + 1
return print('>>>拒绝提醒,生产者继续等待')
else:
producer.inPut('产品')
mutex = mutex + 1
print('>>>生产者生产产品完毕,当前产品队列从', head, '到', rear-1, '处依然存有产品','缓存队列',producer)
class CirQueue():#循环队列队头取元素 队末尾插入元素 #可加可不加object 报错ndentationError: expected an indented block 为什么?
def __init__(self):
self.size =11#队列固定长度
self.Queue=[]#队列以列表形式定义
global head,rear,i
head = 0#存储头队列元素 用于消费者删除
rear = 0#存储尾队列元素 用于生产者放入
def __str__(self):
return str(self.Queue)
def init(self):#初始化 头尾标志依旧指向首位
self.Queue=[0,0,0,0,0,0,0,0,0,0,0]#傻瓜式初始化
global flag
flag = 0
# 判空
def isEmpty(self):
j = 0
# print('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', j)
count = 0
while j != 10: # 将10个元素全部遍历
if self.Queue[j] == 0:
count = count + 1 # 记录元素为空的元素个数
j = j + 1
if count == 10:
return True
return False
# 判满
def isFully(self):
j = 0
# print('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', j)
count = 0
while j != 10: # 将10个元素全部遍历
if self.Queue[j] == 0:
count = count + 1 # 记录元素为空的元素个数
j = j + 1
if count == 0:
return True
return False
#队尾插入元素
def inPut(self,n):#n代表插入的元素
global rear
print(self.Queue)
#print('aaaaaaaaaaaaaaa', rear)
#print('aaaaaaaaaaaaaaa', rear)
if rear == 10:#判满操作不符合循环
return print('队列已满')
else:
i= rear
while self.Queue[i]!=0:
i=i+1
if i==11:#判断 空 元素值全为0
rear = 0
#self.rear=0#正常队尾插入元素操作
elif i>0|i<10:#中间元素不为空
rear=i
elif i==10:#空
return print( '队列已满')
self.Queue[rear]=n #插入元素n
rear = rear+1
#队头取元素
def outPut(self):
global head
j=0
count =0
while j!=10:#将10个元素全部遍历
if self.Queue[j] ==0:
count = count+1#记录元素为空的元素个数
j =j+1
if count == 10:#列表里为空
return print('列表为空不能取元素')
else:
i =head
while self.Queue[i]!=0:
i=i+1
head = i
self.Queue[head] = 0 # 赋值0 ---清除元素操作
"""
测试内容:
test = CirQueue()
#满队列不能放入实现
test.init()#初始化 11个0
print(test)
for i in range(10):#操作放满缓冲区10个元素
test.inPut('产品')
print(test)
print('aaaaaaaaaaaaaaa',rear)
test.inPut(1)#期待此操作过后出现 报满提示
#空队列不能拿出
test.init()
test.outPut()#期待空元素 报空提示
print(test)
"""
#队列初始化
test = CirQueue()
test.init()#初始化 11个0
print(test)
#消费者访问缓冲区拿元素
cus0 = Customer()
cus0.opreate(test)
#期待结果是 消费者判断当前缓存队列为空 调用生产者生产 放入一个产品
print('ssssssssssssssssssssssss',test)
pro0 = Producer()
pro0.opreate(test)
print(test)
pro1 = Producer()
pro1.opreate(test)
print(test)
"""
结果:
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>>消费者请求访问仓库
>>>当前缓冲区为空,消费者不能取用产品
是否调用生产者提供补给(输入1-YES|0-NO) 1
>>>调用生产者
>>>生产者请求访问缓存区
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>>生产者生产产品完毕,当前产品队列从 0 到 0 处依然存有产品 缓存队列 ['产品', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
ssssssssssssssssssssssss ['产品', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>>生产者请求访问缓存区
['产品', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
['产品', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>>生产者生产产品完毕,当前产品队列从 0 到 1 处依然存有产品 缓存队列 ['产品', '产品', 0, 0, 0, 0, 0, 0, 0, 0, 0]
['产品', '产品', 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>>生产者请求访问缓存区
['产品', '产品', 0, 0, 0, 0, 0, 0, 0, 0, 0]
['产品', '产品', 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>>生产者生产产品完毕,当前产品队列从 0 到 2 处依然存有产品 缓存队列 ['产品', '产品', '产品', 0, 0, 0, 0, 0, 0, 0, 0]
['产品', '产品', '产品', 0, 0, 0, 0, 0, 0, 0, 0]
Process finished with exit code
"""
"""
测试内容:
#放入10个产品
test = CirQueue()
test.init()
for i in range(10):
test.inPut('产品')
print(test)
"""