python条件同步线程threading.Condition

condition类里内置了一把RLock锁,有acquire方法和release方法,还有wait,notify,notifyAll方法,

使用acquire方法可以获得RLock锁

使用wait方法就会放掉锁并处于阻塞状态,等其他线程中有使用notify方法时,在wait前的acquire方法处继续线程(注意:而不是紧随wait后面执行)。

notify会唤醒一个wait,但是不会立即跳转到另一个线程的wait处,必须在notify后使用release才能跳转到正在wait的线程的wait语句处。不然不释放锁,wait就继续不了,必须先确认肯定有一个wait时,才可以notify,否则会报错。

import threading
import time
import sys  # 方便调用sys.stdout.write方法取代print方法,因为print具有线程不安全性(换行符会有被拆分输出的机率)


condition = threading.Condition()
item = []  # 列表表示大盘子,最多可以放20个包子
item_id = 0  # 包子的号码


class Producer(threading.Thread):
    def __init__(self, name, n):
        threading.Thread.__init__(self, name=name, args=n)  # 需要先调用父类的构造函数
        self.name = name
        self.n = n  # 要做的包子数

    def run(self):
        global item, item_id
        while self.n != 0:  # 准备开始做一共做n个包子
            condition.acquire()  # 只在读取或改变公有变量/成员时获取线程锁
            if len(item) == 20:
                sys.stdout.write(f'桌子放满了,{self.name}暂停做包子\n')
                condition.wait()
            item.append(item_id)  # 做好的包子放进盘子里
            item_id += 1  # 包子号递增
            sys.stdout.write(f"{self.name}做好了一个包子,放盘子里了{item}\n")
            if len(item) == 1:
                condition.notify()  # 如果盘里现在是1个包子,则通知顾客吃包子
            self.n -= 1  # 需要做的包子数递减
            condition.release()  # 改变公有变量/成员后立即释放锁,以减少线程阻塞时间
            time.sleep(3)  # 3秒钟做一个包子
        else:
            sys.stdout.write(f"{self.name}做包子任务完成了\n")


class Consumer(threading.Thread):
    def __init__(self, name, n):
        threading.Thread.__init__(self, name=name, args=n)  # 需要先调用父类的构造函数
        self.name = name
        self.n = n  # 要吃的包子数

    def run(self):
        global item
        while self.n != 0:
            condition.acquire()  # 只在读取或改变公有变量/成员时获取线程锁
            if len(item) == 0:
                sys.stdout.write(f'{self.name}等待包子中\n')
                condition.wait()
            del item[0]  # 销毁先做好的包子
            sys.stdout.write(f'{self.name}吃掉了一个包子{item}\n')
            if len(item) == 19:
                condition.notify()  # 如果现在盘子里有19个包子,则通知生产者可以继续生产了
            self.n -= 1
            condition.release()  # 改变公有变量/成员后立即释放锁,以减少线程阻塞时间
            time.sleep(1)  # 一秒钟吃一个包子
        else:
            sys.stdout.write(f'{self.name}包子吃够了\n')


if __name__ == '__main__':
    threads = []
    for i in range(1, 3):  # 先建立两个顾客
        threads.append(Consumer('C' + str(i), 10))  # 每个顾客准备消费10个包子
    for i in range(1, 6):  # 再建立5个包子生产者
        threads.append(Producer('P'+str(i), 4))  # 每个生产者各生产4个包子
    for t in threads:
        t.start()
    for t in threads:
        t.join()
    print("完毕")

 

posted @ 2021-09-20 01:03  张永谊  阅读(509)  评论(0)    收藏  举报