【一】生产者和消费者实现原理:


简易思维导图

1.问题背景:避免进程之间出现临界资源的互斥访问的死锁现象
2.解决方式:记录型信号量机制
3.具体细节
- mutex:互斥信号量,初始值是1
- empty:判空信号量
- full:判满信号量
- array[n]:缓冲池存放产品
4.实现好处: 解决死锁


【二】实现细节设计:

  1. 缓存池:循环队列 in,out标记队头和队尾
    利用in,out指针实现加减操作放入拿出产品
    in:指向当前最后产品的存储空间(队位,放入)(rear)
    out:指向最早放入产品存储空间(队头,拿取)(head)
    具体生产者:生产者生产产品,in=(in+1)%n记录更新位置
    具体消费者:消费者拿取产品,out=(out+1)%n记录更新位置
  2. 互斥信号量:初始值为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)

"""