Coding-吸烟者模型

并发编程经典问题之吸烟者。本文简单介绍了问题模型,并提供了一种 Python3 的解决方式。

问题模型
  • 问题描述

    • 假设一个系统有三个抽烟者进程和一个供应者进程。
    • 每个抽烟者不停地卷烟并抽掉它,但是要卷起并抽掉一支烟,抽烟者需要有三种材料:烟草、纸和胶水。三个抽烟者中,第一个拥有烟草、第二个拥有纸,第三个拥有胶水。
    • 供应者进程无限地提供三种材料, 供应者每次将两种材料放到桌子上,拥有剩下那种材料的抽烟者卷一根烟并抽掉它,并给供应者一个信号告诉完成了,供应者就会放另外两种材料在桌上,这种过程一直重复(让三个抽烟者轮流地抽烟)。
  • 问题拓展

    • 假设供应者不并不确定有多少个抽烟者
    • 供应者每次都随机的提供的两种不同的材料
  • 问题分析

    • 供应者与三个抽烟者分别是同步关系:所有抽烟者都空闲时才会提供一份材料;
    • 三个抽烟者卷烟、抽烟和供应的动作是互斥关系;
    • 有且仅有一块共享缓存区,用来存放材料;
    • 有 4 个进程,供应者作为生产者向三个抽烟者提供材料;
Talk is cheap, show me code
  • 下面的例子是线程的实现,用多线程去实现一个纯粹的同步关系,本身是没有意义的,因为完全可以在一个函数里面实现。
  • 但是这种思想可以扩展到进程间的协作、分布式应用间的协作。
from threading import Thread,Condition,Lock,current_thread
from random import randint
from copy import deepcopy
from time import sleep

# 定义卷烟材料
RES_GLU = 0     # 胶水
RES_PAPER = 1   # 纸张
RES_TOBAC = 2   # 烟叶
RES_ALL = [RES_GLU, RES_PAPER, RES_TOBAC]
CONV = {
    RES_GLU:'胶水',
    RES_PAPER:'纸张',
    RES_TOBAC:'烟草',
    }

# 供货者
def supplier(res_con, res_desk):
    print("Supplier Started", flush=True)
    res_con.acquire()
    while True:
        res = deepcopy(RES_ALL)
        loss = randint(0,2)
        res.remove(loss)    # 随机得到两种材料
        res_desk.append(res)
        print("Supplier Data Ready Except: " + CONV[loss], flush=True)
        res_con.notify_all()
        res_con.wait()

# 卷烟、抽烟
def make_cigar(src):
    sleep(1)


# 吸烟者
waked_count = 0
def nicotian(res_con, res_desk, res):
    global waked_count
    th = current_thread()
    print("Nicotian[" + th.name + "] with " + CONV[res] + " Started", flush=True)
    res_con.acquire()
    while True:
        res_con.wait()
        waked_count += 1
        if res_desk and (res not in res_desk[0]):
            make_cigar(res_desk.pop())
            print("Nicotian with " + CONV[res] + " Has Smoked\n", flush=True)
        if waked_count == 3:
            if res_desk:
                print("ERROR: 材料没有被使用", flush=True)
                exit()
            waked_count = 0
            res_con.notify()

def main():
    # 材料桌,初始为空,供应者放入材料,吸烟者取出材料
    res_desk = []
    
    # 材料状态控制
    res_con = Condition(Lock())
    
    # 吸烟者
    res_list = RES_ALL # 给吸烟者分配材料
    thread_nic = []
    for res in res_list:
        thread_nic.append(Thread(target=nicotian, args=(res_con, res_desk, res), daemon=True))
        thread_nic[-1].start()
    sleep(1)
    # 供应者
    thread_supp = Thread(target=supplier, args=(res_con, res_desk), daemon=True)
    thread_supp.start()
    
    input("\n\n===Enter Any Key To Exit===\n\n")
    
if __name__ == '__main__':
    main()

参考文档

http://c.biancheng.net/cpp/html/2603.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值