目录
为什么要引入管程
管程的定义和基本特征
用管程解决生产者消费者问题
结论
本节思维导图
为什么要引入管程
原因:在解决进程的同步与互斥问题时,信号量机制存在编写困难和易出错的问题
能不能设计一种机制,让程序员写程序时不再需要关注复杂的PV操作,让写代码更轻松呢
”管程“:一种更高级同步机制
管程的定义和基本特征
管程是一种特殊的软件模块,由以下部分组成:
- 局部于管程的共享数据结构说明
- 对该数据结构进行操作的一组过程(”过程“即”函数“)
- 对局部于管程的共享数据设置初始值的语句
- 管程有一个名字
管程的基本特征:
- 局部于管程的数据只能被局部于管程的过程所访问
- 一个进程只能通过调用管程内的某个过程才能进入管程访问共享数据
- 每次仅允许一个进程在管程内执行某个内部过程
用管程解决生产者消费者问题
empty和full是标志信号量用于解决同步问题
N为缓冲区的大小
情况一:两个生产者并发执行,依次调用了insert过程
当生产者一调用insert进程时,生产者二想要调用insert进程时会被编译器阻塞(即管程解决生产者消费者问题时,是利用编译器实现各进程互斥地进入管程中地过程)
情况二: 两个消费者进程先执行,生产者后执行
由于缓冲区中产品初始值为0,所以两个消费者进程在并发执行remove函数时都会在wait(empty)处阻塞,然后被挂在等待队列中,此时生产者进程将自己生产的产品放入缓冲区(insert_item(item))中(缓冲区中还能放下新生产的产品)然后判断此时新产品是否是缓冲区中的唯一一个产品(如果是则说明可能会有消费者在等待新产品的生产,此时唤醒排在empty等待队列队头的消费者进程)然后count--,在消费者进程拿走产品前会判断缓冲区在自己拿走产品之前是否已经满了(如果已经满了,证明此时需要唤醒生产者进程去生产因拿走产品导致的缓冲区出现的空位)最后消费者进程拿走产品(最后肯定能拿走,但是拿走之前你得让之前那些因为缓冲区满了而停工的生产者继续生产)
结论
引入管程的目的就是要更方便地实现进程互斥和同步:
- 需要在管程中定义共享数据(生产者消费者问题中的缓冲区)
- 需要在管程中定义用于访问这些共享数据的”入口”,即函数(生产者消费者问题中,可以定义一个函数用于将产品放入缓冲区,再定义一个函数用于从缓冲区取出产品)
- 只有通过这些特定的“入口”才能访问共享数据
- 管程中有很多“入口”,但是每一次只能开放其中一个“入口”,并且只能让一个进程或线程进入(生产者消费者问题中,各进程需要互斥地访问共享缓冲区,管程地这种特性即可保证一个时间段内最多只会有一个进程在访问缓冲区,这种互斥特性是由编译器负责实现地,程序员不需要关心)
- 可在管程中设置条件变量及与之相关的等待/唤醒操作以解决同步问题。可以让一个进程或线程在条件变量上等待(此时,该进程应先释放管程地使用权,也就是让出“入口”):可以通过唤醒操作将等待在条件变量上地进程或线程唤醒
程序员可以用某种特殊地语法定义一个管程,之后其他程序员就可以使用这个管程提供地特定“入口”很方便地实现了进程地同步和互斥了(封装思想)
本节思维导图
~over~