2.6 进程同步 操作系统中引入并发程序设计技术后,程序的执行不再是顺序的,一个程序未执行完而另一个程序便
2.6.4 管程
如果用户进程在进入临界区前没有申请,或者在退出临界区时没有释放,那么互斥就不能正确实现。为了确保互斥的正确实施,操作系统工作者设计了一种靠语言编译来保证互斥正确性的机制——管程机制。
1.管程的引入
用信号量和P、V操作来解决进程同步问题,对于共享变量及信号量变量的操作,将被分散于各个进程中。它的缺点是很明显的:一是易读性差,因为要了解对于一组共享变量及信号量的操作是否正确,必须通读整个系统或者并发程序;二是不利于修改和维护,因为程序的局部性差,所以任一组变量或一段代码的修改都可能影响全局;三是正确性难以保证,因为操作系统或并发程序通常很大,要保证这样一个复杂的系统没有逻辑错误是很难的。例如,后面将会涉及的生产者和消费者问题中,如果将Producer进程中的两个P操作:P(empty)和P(mutex)的位置进行调换,就会出现这样的情况,信号量mutex会先于empty被减1。这样如果缓冲区是满的,empty被置为0,而生产者也被阻塞了。如果这时消费者要读取缓冲区,先对信号量mutex作P操作,但该信号量已为0,所以它也被阻塞了,这种情况就称为死锁。由此可见,在使用信号量的时候必须十分仔细,任何微小的错误都可能造成死锁。
为了解决分散编程带来的困难,采用资源集中管理的方法,用某种数据结构表示某类资源,并将这种数据结构及与资源有关的操作集中在一起,定义为类程或管程,并用类程管理独立资源,用管程管理共享资源,它们两个是能被进程调用的实体。管程是管理进程间同步的机制,它保证进程互斥地访问共享变量,并方便地阻塞和唤醒进程。管程以函数库的形式实现。相比之下,管程比信号量好控制。
2.管程的定义
系统中的各种硬件资源和软件资源均可用数据结构抽象地描述,即用少量信息和对该资源所执行的操作来表明该资源,而忽略它们的内部结构和实现细节。例如,一个FIFO队列可用它的队长、队首、队尾及在该队列上所执行的一组操作来表示。当共享资源用数据结构表示时,资源管理程序可用对该数据结构进行操作的一组过程来表示。把这样一组相关的数据结构和过程称为管程。Hansan为管程下的定义:一个数据结构和能为并发进程所执行的一组操作,这组操作能同步进程和改变管程中的数据。由定义可知,管程由三部分组成:
局部于管程的共享数据说明;
对该数据结构进行操作的一组过程;
对局部于管程的数据设置初始值的语句。
管程机制提供了与信号量机制相同的表达能力,但它更容易控制。它可用来实现进程同步,如取名为monitor_name的管程,其语法如下:
3.管程的特点
管程内的局部变量只能被局部于管程内的过程所访问。反之亦然,即局部于管程内的过程只能访问管程内的变量。
任何进程只能通过管程提供的过程入口进入管程。
任何时刻最多只能有一个进程在管程中执行。
保证进程互斥地进入管程是由编译器负责的,也就是说,管程是一种编程语言的构件,它的实现需要得到编译器的支持。
4.同步、互斥和条件变量
在实现一个管程时必须考虑以下3个问题。
(1)互斥
当有几个进程调用某管程时,仅允许一个进程进入管程,其他调用者必须等待,即各进程必须互斥地进入管程。这一点通常得到编译程序的支持,编译程序对每一个管程都将自动地产生一个互斥信号量,并将它的初值置为1。
(2)同步
在管程中,必须设置两个同步操作原语wait和signal。当某进程通过管程请求访问某共享数据而未能满足时,管程便调用wait原语使该进程等待,并将它排在等待队列上。仅当另一进程访问完该共享数据并释放之后,管程才可调用signal原语,唤醒等待队列中队首进程。
(3)条件变量
通常,等待的原因可有多个,为了区别它们,引入条件变量cond。管程中对每个条件变量都予以说明,其形式为“cond:condition”。该变量应置于wait和signal之前。例如,由于共享数据被占用而使调用进程等待,该条件变量形式为“nonbusy:condition”。此时,wait原语应该为nonbusy.wait,相应地,signal应改为nonbusy.signal。如果进程队列是优先级队列,则应表示为cond.wait(P)及cond.signal(P)。
5.利用管程解决生产者-消费者问题
建立一个管程PC,它包括两个过程put(item)和get(item),它们分别执行把生产的消息放入缓冲池和从缓冲池取出消息的操作,设置一变量count表示缓冲池已存消息数目。算法描述如下:
相应的生产者和消费者可描述为:
关于"最后阶段,真题的正确打开方式_备考经验_考研帮"有15名研友在考研帮APP发表了观点
扫我下载考研帮
最新资料下载
2021考研热门话题进入论坛
考研帮地方站更多
你可能会关心:
来考研帮提升效率