管程的定义:
管程是由局部于自己的若干公共变量及其说明和所有访问这些公共变量的过程所组成的软件模块。
管程的组成:
管程的属性:
共享性:管程可被系统范围内的进程互斥访问,属于共享资源。
安全性:管程的局部变量只能由管程的过程访问,不允许进程或其它管程直接访问,管程也不能访问非局部于它的变量。
互斥性:多个进程对管程的访问是互斥的。任一时刻,管程中只能有一个活跃进程。
封装性:管程内的数据结构是私有的,只能在管程内使用,管程内的过程也只能使用管程内的数据结构。进程通过调用管程的过程使用临界资源。管程在Java中已实现。
管程入口处的等待队列:
管程是互斥进入的,所以当一个进程试图进入一个巳被占用的管程时它应当在管程的入口处等待,因而在管程的入口处应当有一个进程等待队列,称作入口等待队列。
管程内的资源等待队列:
管程是用于管理资源的,当进入管程的进程因资源被占用等原因不能继续运行时使其等待,即将等待资源的进程加入资源等待队列,该队列由条件变量维护。资源等待队列可以由多个,每种资源一个队列。
管程内的紧急等待队列:
当一个进入管程的进程执行等待操作wait时,其它进程应该被允许进入管程;
当一个进入管程的进程执行唤醒操作signal时(如P唤醒Q),管程中便存在两个同时处于活动状态的进程,由于任一时刻,管程中只能有一个活跃进程。所以处理办法为:
(1)P等待Q继续,直到Q退出或等待。
(2)Q等待P继续,直到P等待或退出。
(3)规定唤醒signal为管程中最后一个可执行的操作。
管程就相当于C语言中的函数,使用管程就相当于“函数调用”
引入管程的目的:更方便地实现进程的互斥和同步。
“封装思想” :将一套复杂的代码程序封装到一个函数中,只需要调用这个函数名就可以进行这个程序,避免了重复工作。
管程的实现:
mutex
信号量mutex管理管程入口处的等待队列,供管程中过程互斥调用,初值为1。
进程调用管程中的任何过程时,应执行P(mutex);进程退出管程时应执行V(mutex)开放管程,以便让其他调用者进入。
执行wait操作的进程需要释放信号量mutex,不在mutex信号量上等待,而在其它条件变量(或信号量)上等待。
next和next-count
信号量next管理管程内的紧急等待队列其初值为0,凡发出signal操作的进程应该用P(next)挂起自己,加入紧急等待队列,直到被释放进程退出管程或产生其他等待条件。
进程在退出管程的过程前,须检查是否有别的进程在信号量next(即紧急等待队列)上等待,若有,则用V(next)唤醒它。next-count初值为0,用来记录在next (即紧急等待队列)上等待的进程个数。
x-sem和 x-count
信号量x-sem用来管理资源等待队列,其初值为0,进程申请资源得不到满足时,执行P(x-sem)挂起,加入x-sem所代表的资源队列。由于释放资源时,需要知道是否有别的进程在等待资源,用计数器x-count(初值为0)记录等待资源(即资源等待队列中)的进程数。
执行signal操作时,应让等待资源(即资源等待队列中)的诸进程中的某个进程立即恢复运行,而不让其他进程抢先进入管程,这可以用V(x-sem)来实现。
enter过程:enter过程、leave过程、条件型变量c、wait(c) 、signal(c):
一个进程进入管程前要提出申请,一般由管程提供一个外部过程--enter过程。如Monitor.enter()表示进程调用管程Monitor外部过程enter进入管程。
1. leave过程:
当一个进程离开管程时,如果紧急队列不空,那么它就必须负责唤醒紧急队列中的一个进程,此时也由管程提供一个外部过程—leave过程,如Monitor.leave()表示进程调用管程Monitor外部过程leave离开管程。
2. 条件型变量c:
条件型变量c实际上是一个指针,它指向一个等待该条件的PCB队列。如notfull表示缓冲区不满,如果缓冲区已满,那么将要在缓冲区写入数据的进程就要等待notfull,即wait(notfull)。相应的,如果一个进程在缓冲区读数据,当它读完一个数据后,要执行signal(notempty),表示已经释放了一个缓冲区单元。
3. wait(c):
wait(c)表示为进入管程的进程分配某种类型的资源,如果此时这种资源可用,那么进程使用,否则进程被阻塞,进入紧急队列。
4. signal(c):
signal(c)表示进入管程的进程使用的某种资源要释放,此时进程会唤醒由于等待这种资源而进入紧急队列中的第一个进程。
总结:
虽然后面的几段扩充材料我现在还看不懂,不过我相信我一定很快就会理解的。加油,这个过程要靠自己来实现!