程序结构之管程

来源:互联网 发布:颂党恩 知党史 促成长 编辑:程序博客网 时间:2024/05/29 17:22

管程是一种程序结构,是一种进程同步机制。之前的PV操作和信号量尽管是有效、简单易用的进程同步机制,但是信号机制存在缺陷,即P、V操作的使用是分散在各个进程之间的,很不利于对临界资源的统一管理,另一个是P、V操作原语的不正确使用会造成死锁。

管程的基本思路是:将分散在各个进程间的临界区集中起来进行统一控制和管理,并且将系统中的共享资源用数据结构抽象地描述出来。然后对临界区的访问通过“管程”进行统一管理。管程就是由若干个数据结构、变量以及方法(函数)所组成的一种特殊的结构,它的形式表现是一种特殊的模块或软件包。进程可以使用管程中的方法,但是不允许直接使用管程中的内部数据结构,管程内部定义的数据结构只可以由它内部所定义的方法(函数)直接访问。

信号量机制和管程机制,从思想上看,有点像面向过程的程序设计与面向对象的程序设计之间的关系,管程机制的思想有点面向对象程序设计。

管程的特点:

  1、互斥性:任何时刻只能最多有一个进程进入管程活动,其他想进入的进程必须等待。管程是程序设计语言是一个成分或结构,因此,在支持管程的编译器环境下,管程的互斥是管程的固有特性,应用程序员可以直接利用该特性。

  2、安全性:管程中的局部变量只能由该管程的方法或函数来访问,其他进程或管程是不能够对该局部变量进行直接访问,同时一个管程中的方法或函数也不允许访问非局部于它的变量。

  3、共享性:管程中的特定的方法或函数可以被其他的管程或进程访问,这样的方法或函数,在管程中有特殊的说明。

管程是程序语言的成分或结构,依赖于编译器,不必去创建或撤销,但是进程是动态是生命实体,需要创建或撤销。

管程提出的一个目标就是将跟共享资源相关的同步操作统一管理,而跟共享资源相关的临界区是分散在各个进程代码之间的。

管程是为了安全高效实现进程同步而引入的概念和机制,而进程是为了实现资源分配和保护而引入的概念

管程定义的是公共的数据结构,由各个进程在互斥下共享,而进程定义的是私有的数据结构,只能由本进程访问。

管程是由对应的进程所调用,管程与调用它的进程是不能并发工作的,但是进程具有并发性,可以并行执行。

汉森方法实现管程:规定管程中的函数执行的signal()操作一定是函数体中的最后一个操作,提出应该让执行signal()操作的进程立即退出管程,有四个原语:

1、wait原语:即等待原语,当一个进程由于自身原因运行不下去了,就执行该原语,从而放开管程,让其他想进入管程的进程能够进入,自己则进入阻塞状态。

2、signal原语:即发送原语,一个进程执行了signal()原语操作后,就会唤醒在相应条件变量上的等待进程队列中的一个进程,该进程就可以进入管程。至于会唤醒等待队列中的哪一个进程,则由系统的唤醒策略或算法决定。假如等待队列没有进程,则signal()操作没有任何影响。在Hansen方法中,执行signal()原语的进程需要立即离开管程。

3、check原语:即检查原语。当执行这条原语,假如管程可用,则该进程进入管程,同时将管程关闭;假如执行这条原语,管程是不可用的,那么执行这条原语的进程就进入等待调用状态。

4、release原语:即释放原语,当执行了这一条原语的进程,此时没有其他进入管程并且不处于阻塞状态的进程,那么在有等待调用状态的进程时,就唤醒一个等待调用状态进程。假如没有等待调用状态的进程时,就将管程开放。

用管程来解决问题示例:

一、管程来解决生产者/消费者问题 

Struct Monitor { condition NF,NE; int Buffer[n]; int k = 0,t = 0,count = 0; define Add(int),Remove(int); use wait(),signal(),check(),release(); void init() //初始化局部变量和条件变量 { count = 0;k = 0;t = 0;NF = 0;NE = 0; } vodi Add(int i) { check(); if(count ==n) wait(NF); Buffer[k] = i; k = (k+1)%n; count++; signal(NE); release(); } void Remove(int &i) { check(); if(count == 0)wait(NE); i = Buffer[t]; t = (t+1)%n; count–; signal(NF); release(); } }[objc] view plain copy 在CODE上查看代码片派生到我的代码片 process producteri()//i = 1,2…,m { int x; x = 生产一个产品(整数) Add(x); }process consumerj()//j = 1,2,…,r { int x; Remove(x); 消费该产品(整数); }

二、用管程来解决优先写着的读者/写着问题 
先写者的读者/写着问题要求是: 
读者共享; 
写着互斥; 
有读者在读,写着不可写; 
写着在写,读者不可读; 
当读者在读时,写着提出写的要求,后面的读者就不允许进入读文件; 
当里面的读者读完时,由写着进入写; 
当写着写完后,优先唤醒等待的写着,如果没有写着等待,才唤醒等待的读者进行读;

struct Monitor { condition RR,WW; int ReaderCnt,WriterCnt; define StartRead,EndRead,StartWrite,EndWrite; use wait,signal,check,release; void StartRead() { check(); if(WriterCnt>0)wait(RR); ReaderCnt++; signal(RR); release(); } void EndRead() { check(); ReaderCnt–; if(ReaderCnt == 0)signal(WW); release(); } void StartWrite() { check(); WriterCnt++; if(ReadCnt>0 || WriterCnt>1)wait(WW); release(); } void EndWrite() { check(); WriterCnt–; if(WriterCnt>0)signal(WW); else signal(RR); release(); } void init() { ReaderCnt=0;WriterCnt=0;RR=0;WW=0; } }[objc] view plain copy 在CODE上查看代码片派生到我的代码片 process reader() { ReadWriter.StartRead(); 读文件; ReadWriter.EndRead(); }process writer() { ReadWriter.StartWrite(); 写文件; ReadWriter.EndWrite(); }


0 0
原创粉丝点击