进程
顺序程序
程序:一个指令序列
早期单道程序系统中,内存除操作系统外,只有一个用户程序在里面,系统内其他资源也有这个程序单独使用,不与其他用户共享。因此单道程序就严格按顺序方式执行。
特点:
- 顺序性:每个动作只能在下一个动作完成后才开始
- 封闭性:只有程序本身的动作才能改变程序运行的环境
-
并发执行
多道程序:在内存中同时存放多道程序,在管理程序的控制下在CPU上交替的运行。由于CPU执行指令的方式一般是流水线方式,即顺序执行,所以在每一时刻在CPU上真正执行的程序只有一个。从宏观上看,系统中的多个程序同时得到执行,即实现了程序的并发执行
特征: 失去了封闭性:多个程序共享资源,资源使用状态受并发状态共同影响执行时的相对速度不确定,每个程序都会走走停停何时发生控制转换并非完全由程序本身确定,而与当前环境有关,具有一定的随机性
- 程序与计算不再一一对应:程序:指令的有序集合,是静态概念计算:指令在处理及上的执行过程,是动态概念在并发执行过程中,一个共享程序可被多个用户作业调用,从而形成多个计算
- 并发程序在执行期间相互制约不再像顺序执行那样顺序连贯,而是具有执行—暂停—执行的活动规律
进程概念
定义:
- 一个具有独立功能的程序关于某个数据集合的一次运行活动
- 程序在并发环境中的执行过程
进程与程序的区别:
- 动态性:程序是静态被动的,本身可做为一种软件资源长期保存进程是程序一次执行的过程,动态主动的概念,有一定的生命周期
- 并发性:是一个独立的运行单位(进程中不仅包含相应的程序和数据还有一系列描述其活动情况的数据结构),作为申请资源和调度单位的存在,能与其他进程并发执行。程序不能作为一个独立运行的单位而并发执行;具有顺序执行的性质,不同模块通过相互调用实现控制和转移
- 非对应性:程序和进程无一一对应关系,一个程序可被多个进程共用一个进程在其活动中又可顺序地执行若干程序
- 异步性:各个进程在并发执行的过程中会产生相互制约的关系,造成各自进度的不可预测性程序是静态的,不存在异步特征
进程的特征:
- 动态性
- 并发性
- 调度行:申请资源的单位,被调度的单位
- 异步性:各个进程相互制约,失去再现性;各个进程向前推进的速度不可预知,异步方式运行
- 结构性:由程序段(规定执行的任务)、数据段(程序操作的对象)、控制结构(进程描述的信息和控制信息)组成
进程的基本状态:
进程的动态性质是由其状态及其转换决定的
三种最基本的状态(123)
- 运行状态:当前进程已经分配到CPU,程序在处理机上正在执行的状态
- 就绪状态:已经具备运行条件,处于等待分配CPU的状态
- 阻塞状态:进程因等待某种事件发生而暂时不能运行状态(不具备运行条件)
- 新建状态:进程刚刚被创建,尚未放入就绪队列
- 终止状态:完成自己的任务而正常终止或者是出现某些错误故障而被迫中止
进程描述
进程控制块
进程的活动是通过在CPU上执行一些列的程序和对应数据进行操作体现的,因此程序和数据是组成进程的实体
但是仍需要一个数据结构描述当前进程的状态、本身的特性、对资源的占用及调度情况,这种数据结构成为进程控制块。
进程映像:通常由程序、数据集合、栈和PCB四部分组成;这四部分构成进程在系统中存在和活动的实体
进程控制块的组成
是进程组成中最关键的部分,其中含有进程的描述信息和控制信息,是进程动态性的集中反映,是系统对进程实行识别和控制的依据
- 进程名:唯一标志对应进程的一个标识符和数字
- 特征信息
- 进程状态信息
- 调度优先权
- 通信信息
- 现场保护区:当对应进程由于某种原因放弃使用CPU时需要把它的一部分与运行环境有关的信息保存起来,以便在重新获得CPU时恢复正常运行
- 资源需求、分配、控制方面的信息
- 进程实体信息:程序和数据的存储情况,在内存或外存的地址或大小
- 族系信息
- 其他信息
进程控制块的作用
- 每个进程有唯一的进程控制块
- 操作系统根据PCB对进程实施管理和控制
- 进程的动态、并发特征是利用PCB表现出来的
- PCB是进程存在的唯一标识;当系统创建一个新进程,会先为他建立一个PCB,进程终止后,系统就回收PCB,该进程在系统中就不存在了
进程队列(进程的组织方式)
- 线性方式
- 最简单最容易实现
- 限定了系统中存在的进程最大数目;在执行CPU调度时,未选择合理的进程投入运行,往往需要对整个表进行扫描, 降低了调度的效率
- 链接方式
- 按照各进程的不同状态将他们的PCB放在不同的队列中
- 索引方式
- 利用索引表及在不同状态进程的PCB地址;状态相同的进程PCB组织在同一索引表中,每个索引表目中存放一个PCB地址,各索引表内存的起始地址放在专用的指针单元中
进程管理
进程图
族系关系:由父进程创建子进程,子进程在创建子进程,从而构成一棵树形进程族系图
结点表示进程
进程的状态
进程创建(创建态)
- 调度新作业
- 用户登录
- 操作系统提供特定的服务
- 派生新进程
进程终止(终止态)
正常终止:
当一个进程完成自己的任务后,使用exit系统调用,要求操作系统删除它
异常终止:
在运行过程中如果出现某些错误或故障,会导致进程终止:运行超时、内存不足、越界错误、保护错误、算术运算错误、等待超时、IO故障、非法指令、特权指令、数据不可用
外部干扰:
操作员or操作系统的干预
进程阻塞
进程唤醒
进程状态的转化
进程控制
主要是对系统中所有的进程实施有效的管理,具有创建新进程、撤销已有的进程、实现进程状态转化等功能
原语
进程通信
共享存储
管道通信
消息传递
线程
线程的属性
线程的实现方式
用户级线程
内核级线程
多线程模型
多对一模型
一对一模型
多对多模型
进程的同步和互斥
进程的异步性:各并发执行的进程是以各自独立的、不可预知的速度推进的。
同步
读进程和写进程并发地运行,由于并发必然导致异步性,因此“写数据”和“读数据”两个操作执行的先后顺序是不确定的。而实际应用中,又必须按照“写数据→读数据”的顺序来执行的。
如何解决这种异步问题,就是“进程同步”所讨论的内容。
同步亦称直接制约关系,它是指为完成某种任务而建立的两个或多个进程,这些进程因为需要在某些位置上协调它们的工作次序而产生的制约关系。
进程间的直接制约关系就是源于它们之间的相互合作。
互斥
概念
逻辑上无关的两个或多个进程由于争用统一资源而发生的相互制约关系
临界资源:一个时间段内只允许一个进程使用。
我们把一个时间段内只允许一个进程使用的资源称为临界资源。
许多物理设备(比如摄像头、打印机)属于临界资源。此外还有许多变量、数据、内存缓冲区等都属于临界资源。
对临界资源的访问,必须互斥地进行。互斥,亦称间接制约关系。
进程互斥指当一个选程访问某临界资时,另一个想要访问该临界资源的进程必须等待。当前访问临界资源的进程访问结束,释放该资源之后,另一个进程才能去访问临界资源。
状态
原则
1.空闲让进。临界区空闲时,可以允许一个请求进入临界区的进程立即进入临界区;
2.忙则等待。当已有进程进入临界区时,其他试图进入临界区的进程必须等待;
3.有限等待。对请求访问的进程,应保证能在有限时间内进入临界区(保证不会饥饿)
4.让权等待。当进程不能进入临界区时,应立即释放处理机,防止进程忙等待。
软件实现
单标志法
算法思想:两个进程在访问完临界区后会把使用临界区的权限转交给另一个进程。也就是说每个进程进入临界区的权限只能被另一个进程赋予
turn表示当前允许进入临界区的进程号,而只有当前允许进入临界区的进程在访问了临界区之后,才会修改turn的值。也就是说,对于临界区的访问,一定是按PO→P1→PO→P1→.…这样轮流访问。
这种必须“轮流访问”带来的问题是,如果此时允许进入临界区的进程是PO,而PO一直不访问临界区,那么虽然此时临界区空闲,但是并不允许P1访问。
因此,单标志法存在的主要问题是:违背“空闲让进”原则。
双标志先检查法
算法思想:设置一个布尔型数组flag[],数组中各个元素用来标记各进程想进入临界区的意愿,比如“flag[0] =ture”意味着0号进程P0现在想要进入临界区。
每个进程在进入临界区之前先检查当前有没有别的进程想进入临界区,如果没有,则把自身对应的标志flag[i]设为true,之后开始访问临界区。
因此,双标志先检查法的主要问题是:违反“忙则等待”原则。
原因在于,进入区的“检查”和“上锁”两个处理不是一气呵成的。“检查”后,“上锁”前可能发生进程切换。
双标志后检查法
算法思想:双标志先检查法的改版。前一个算法的问题是先“检查”后“上锁”,但是这两个操作又无法一气呵成,因此导致了两个进程同时进入临界区的问题。因此,人们又想到先“上锁”后“检查’的方法,来避免上述问题。
因此,双标志后检查法虽然解决了“忙则等待”的问题,但是又违背了“空闲让进”和“有限等待”原则,会因各进程都长期无法访问临界资源而产生“饥饿”现象。
peterson算法
算法思想:双标志后检查法中,两个进程都争着想进入临界区,但是谁也不让谁,最后谁都无法进入临界区。Gary L.Peterson想到了一种方法,如果双方都争着想进入临界区,那可以让进程尝试“孔融让梨”,主动让对方先使用临界区。
Peterson算法用软件方法解决了进程互斥问题,遵循了空闲让进、忙则等待、有限等待三个原则,但是依然未遵循让权等待的原则。
硬件实现
中断屏蔽
TestAndSet
简称TS指令,也有地方称为TestAndSetLock指令,或TSL指令
TSL指令是用硬件实现的,执行的过程不允许被中断,只能一气呵成。
以下是用c语言描述的逻辑
若刚开始lock是 false,则TSL返回的old值为 false,while循环条件不满足,直接跳过循环,进入临界区。若刚开始lock是true,则执行TLS后old返回的值为true,while循环条件满足,会一直循环,直到当前访问临界区的进程在退出区进行“解锁”。
相比软件实现方法,TSL指令把“上锁”和“检查”操作用硬件的方式变成了一气呵成的原子操作。
优点:实现简单,无需像软件实现方法那样严格检查是否会有逻辑漏洞;适用于多处理机环境。
缺点:不满足“让权等待”原则,暂时无法进入临界区的进程会占用cPU并循环执行TSL指令,而导致“忙等”。
swap
有的地方也叫Exchange指令,或简称XCHG指令。
Swap指令是用硬件实现的,执行的过程不允许被中断,只能一气呵成。
以下是用c语言描述的逻辑
逻辑上来看Swap和TSL并无太大区别,都是先记录下此时临界区是否已经被上锁(记录在 old变量上),再将上锁标记lock设置为true,最后检查old,如果old为false则说明之前没有别的进程对临界区上锁,则可跳出循环,进入临界区。
优点:实现简单,无需像软件实现方法那样严格检查是否会有逻辑漏洞;适用于多处理机环境。
缺点:不满足“让权等待”原则,暂时无法进入临界区的进程会占用cPU并循环执行TSL指令,从而导致“忙等”。
信号量
1.在双标志先检查法中,进入区的“检查”、“上锁”操作尤法一气呵成,从而导致了两个进程有可能同时进入临界区的问题;
2.所有的解决方案都无法实现“让权等待”
1965年,荷兰学者Dijkstra提出了一种卓有成效的实现进程互斥、同步的方法――信号量机制
信号量机制
用户进程可以通过使用操作系统提供的一对原语来对信号量进行操作,从而很方便的实现了进程互斥、进程同步。
信号量其实就是一个变量(可以是一个整数,也可以是更复杂的记录型变量),可以用一个信号量来表示系统中某种资源的数量,比如:系统中只有一台打印机,就可以设置一个初值为1的信号量。
原语
原语是一种特殊的程序段,其执行只能一气呵成,不可被中断。
原语是由关中断/开中断指令实现的。
软件解决方案的主要问题是由“进入区的各种操作无法一气呵成”,因此如果能把进入区、退出区的操作都用“原语”实现,使这些操作能“一气呵成”就能避免尚题。
一对原语: wait(S)原语和signal(S)原语,可以把原语理解为我们自己写的函数,函数名分别为wait和signal,括号里的信号量s其实就是函数调用时传入的一个参数。
wait、signal原语常简称为P、v操作(来自荷兰语proberen和verhogen)。因此,做题的时候常把wait(S)、signal(S)两个操作分别写为P(S)、v(S)
记录型信号量
S.value的初值表示系统中某种资源的数目。
对信号量s的一次Р操作意味着进程请求一个单位的该类资源,因此需要执行S.value—,表示资源数减1,当S.value <0时表示该类资源已分配完毕,因此进程应调用block原语进行自我阻塞(当前运行的进程从运行态→阻塞态),主动放弃处理机,并插入该类资源的等待队列s.L中。可见,该机制遵循了“让权等待”原则,不会出现“忙等”现象。
对信号量s的一次v操作意味着进程释放一个单位的该类资源,因此需要执行S.value++,表示资源数加1,若加1后仍是S.value <= o,表示依然有进程在等待该类资源,因此应调用wakeup原语唤醒等待队列中的第一个进程(被唤醒进程从阻塞态→就绪态)。
用信号量机制实现进程互斥
用信号量机制实现进程同步
用信号量机制实现前驱关系![image.png](/uploads/projects/redamancy-5shnz@dh5ho8/1b08f6b6e0d8d5b9134f135166aa9023.png)
生产者-消费者问题
系统中有一组生产者进程和一组消费者进程,生产者进程每次生产一个产品放入缓冲区,消费者进程每次从缓冲区中取出一个产品并使用。(注:这里的“产品”理解为某种数据)
生产者、消费者共享一个初始为空、大小为n的缓冲区。
- 只有缓冲区没满时,生产者才能把产品放入缓冲区,否则必须等待。(同步)
- 只有缓冲区不空时,消费者才能从中取出产品,否则必须等待。(同步)
- 缓冲区是临界资源,各进程必须互斥地访问。(互斥)
PV操作题目分析步骤:
1.关系分析。找出题目中描述的各个进程,分析它们之间的同步、互斥关系。
2.整理思路。根据各进程的操作流程确定P、V操作的大致顺序。
3.设置信号量。设置需要的信号量,并根据题目条件确定信号量初值。(互斥信号量初值一般为1,同步信号量的初始值要看对应资源的初始值是多少)
semaphore mutex = 1;
//互斥信号量,实现对缓冲区的互斥访问
semaphore empty = n;
//同步信号量,表示空闲缓冲区的数量
semaphore full = 0 ;
//同步信号量,表示产品的数量,也即非空缓冲区的数量
若此时缓冲区内已经放满产品,则empty=0,full=n。
则生产者进程执行①使mutex变为0,再执行②,由于已没有空闲缓冲区,因此生产者被阻塞。由于生产者阻塞,因此切换回消费者进程。消费者进程执行③,由于mutex为0,即生产者还没释放对临界资源的“锁”,因此消费者也被阻塞。
这就造成了生产者等待消费者释放空闲缓冲区,而消费者又等待生产者释放临界区的情况,生产者和消费者循环等待被对方唤醒,出现“死锁”。
同样的,若缓冲区中没有产品,即full=0,empty=n。按③④①的顺序执行就会发生死锁。
因此:
实现互斥的P操作一定要在实现同步的P操作之后。
V操作不会导致进程阻塞,因此两个v操作顺序可以交换。
生产者消费者问题是一个互斥、同步的综合问题。
对于初学者来说最难的是发现题目中隐含的两对同步关系。
有时候是消费者需要等待生产者生产,有时候是生产者要等待消费者消费,这是两个不同的“一前一后问题”,因此也需要设置两个同步信号量。
多生产者-多消费者问题
是否可以删除metex
当缓冲区=1
结论:即使不设置专门的互斥变量mutex,也不会出现多个进程同时访
问盘子的现象
原因在于:本题中的缓冲区大小为1,在任何时刻,apple、orange、 plate三个同步信号量中最多只有一个是1。因此在任何时刻,最多只有一个进程的P操作不会被阻塞,并顺利地进入临界区
如果缓冲区的大小>1
解决“多生产者-多消费者问题”的关键在于理清复杂的同步关系。
在分析同步问题(一前一后问题)的时候不能从单个进程行为的角度来分析,要把“一前一后”发生的事看做是两种“事件”的前后关系。
比如,如果从单个进程行为的角度来考虑的话,我们会有以下结论:
如果盘子里装有苹果,那么一定要女儿取走苹果后父亲或母亲才能再放入水果如果盘子里装有橘子,那么一定要儿子取走橘子后父亲或母亲才能再放入水果
这么看是否就意味着要设置四个同步信号量分别实现这四个“一前一后”的关系了?
正确的分析方法应该从“事件”的角度来考虑,我们可以把上述四对“进程行为的前后关系”抽象为一对“事件的前后关系”
盘子变空事件→放入水果事件。“盘子变空事件”既可由儿子引发,也可由女儿引发;“放水果事件”既可能是父亲执行,也可能是母亲执行。
这样的话,就可以用一个同步信号量解决问题了
抽烟者问题
假设一个系统有三个抽烟者进程和一个供应者进程。每个抽烟者不停地卷烟并抽掉它,但是要卷起并抽掉一支烟,抽烟者需要有三种材料:烟草、纸和胶水。三个抽烟者中,第一个拥有烟草、第二个拥有纸、第三个拥有胶水。供应者进程无限地提供三种材料,供应者每次将两种材料放桌子上,拥有剩下那种材料的抽烟者卷一根烟并抽掉它,并给供应者进程一个信号告诉完成了,供应者就会放另外两种材料再桌上,这个过程一直重复(让三个抽烟者轮流地抽烟)
本质上这题也属于“生产者-消费者”问题,更详细的说应该是“可生产多种产品的单生产者-多消费者”。
吸烟者问题可以为我们解决“可以生产多个产品的单生产者”问题提供一个思路。
值得吸取的精华是:“轮流让各个吸烟者吸烟”必然需要“轮流的在桌上放上组合一、二、三”,注意体会我们是如何用一个整型变量i 实现这个“轮流”过程的。
如果题目改为“每次随机地让一个吸烟者吸烟”,我们有应该如何用代码写出这个逻辑呢?
若一个生产者要生产多种产品(或者说会引发多种前驱事件),那么各个V操作应该放在各自对应的“事件”发生之后的位置。
读者-写者问题
有读者和写者两组并发进程,共享一个文件,当两个或两个以上的读进程同时访问共享数据时不会产生副作用,但若某个写进程和真他进程(读进程或写进程〉同时访问共享数据时则可能导致数据不一致的错误。
因此要求:
①允许多个读者可以同时对文件执行读操作;
②只允许一个写者往文件中写信息;
③任一写者在完成写操作之前不允许其他读者或写者工作;
④写者执行写操作前,应让已有的读者和写者全部退出。两类进程:写进程、读进程
互斥关系:写进程一写进程、写进程―读进程。读进程与读进程不存在互斥问题。
写者进程和任何进程都互斥,设置一个互斥信号量rw,在写者访问共享文件前后分别执行P、v操作。读者进程和写者进程也要互斥,因此读者访问共享文件前后也要对rw执行P、v操作。
如果所有读者进程在访问共享文件之前都执行P(rw)操作,那么会导致各个读进程之间也无法同时访问文件。Key:读者写者问题的核心思想――怎么处理该问题呢?
P(rw)和V(rw)其实就是对共享文件的“加锁”和“解锁”。既然各个读进程需要同时访问,而读进程与写进程又必须互斥访问,那么我们可以让第一个访问文件的读进程“加锁”,让最后一个访问完文件的读进程“解锁”。可以设置一个整数变量count来记录当前有几个读进程在访问文件。
潜在的问题:只要有读进程还在读,写进程就要一直阻塞等待,可能“饿死”。
因此,这种算法中,读进程是优先的。
他
一个写进程在一个读进程进行时访问,会被阻塞再P(rw)处,然后等该读的文件读完后,释放rw,写进程才得以进行,在此之前进入的读进程都只能等这个写进程结束。
第一种写法里,若有源源不断的都进程进入,会导致写进程的饥饿
第二种写法是一种相对公平的服务方法。
总结
读者-写者问题为我们解决复杂的互斥问题提供了一个参考思路。
其核心思想在于设置了一个计数器count用来记录当前正在访问共享文件的读进程数。我们可以用count的值来判断当前进入的进程是否是第一个/最后一个读进程,从而做出不同的处理。
另外,对count变量的检查和赋值不能一气呵成导致了一些错误,如果需要实现“一气呵成”,自然应该想到用互斥信号量。
最后,还要认真体会我们是如何解决“写进程饥饿”问题的。
绝大多数的考研PV操作大题都可以用之前介绍的几种生产者-消费者问题的思想来解决,如果遇到更复杂的问题,可以想想能否用读者写者问题的这几个思想来解决。
哲学家进餐问题
一张圆桌上坐着5名哲学家,每两个哲学家之间的桌上摆一根筷子,桌子的中间是一碗米饭。哲学家们倾注毕生的精力用于思考和进餐,哲学家在思考时,并不影响他人。只有当哲学家饥饿时,才试图拿起左、右两根筷子(一根一根地拿起)。如果筷子已在他人手上,则需等待。饥饿的哲学家只有同时拿起两根筷子才可以开始进餐,当进餐完毕后,放下筷子继续思考。
分析
1.关系分析。系统中有5个哲学家进程,5位哲学
家与左右邻居对其中间筷子的访问是互斥关系。2.整理思路。这个问题中只有互斥关系,但与之前
遇到的问题不同的事,每个哲学家进程需要同时持有两个临界资源才能开始吃饭。如何避免临界资源分配不当造成的死锁现象,是哲学家问题的精髓。
3.信号量设置。定义互斥信号量数组
chopstick[5]={1,1,1,1,1}用于实现对5个筷子的互斥访问。并对哲学家按O~4编号,哲学家i左边的筷子编号为i,右边的筷子编号为(i+1)%5。
代码
死锁
预防死锁
1、可以对哲学家进程施加一些限制条件,比如最多允许四个哲学家同时进餐。这样可以保证至少有一个哲学家是可以拿到左右两只筷子的
2、要求奇数号哲学家先拿左边的筷子,然后再拿右边的筷子,而偶数号哲学家刚好相反。用这种方法可以保证如果相邻的两个奇偶号哲学家都想吃饭,那么只会有其中一个可以拿起第一只筷子,另一个会直接阻塞。这就
避免了占有一支后再等待另一只的情况。
3、当左右两边的筷子都能拿起来的时候才能拿起筷子
先0->1->2的情况
更准确的说法应该各哲学家拿筷子这件事必须互斥的执行。
这就保证了即使一个哲学家在拿筷子拿到一半时被阻塞,也不会有别的哲学家会继续尝试拿筷子。这样的话,当前正在吃饭的哲学家放下筷子后,被阻塞的哲学家就可以获得等待的筷子了。
总结
哲学家进餐问题的关键在于解决进程死锁。
这些进程之间只存在互斥关系,但是与之前接触到的互斥关系不同的是,每个进程都需要同时持有两个临界资源,因此就有“死锁”问题的隐患。
如果在考试中遇到了一个进程需要同时持有多个临界资源的情况,应该参考哲学家问题的思想,分析题中给出的进程之间是否会发生循环等待,是否会发生死锁。
可以参考哲学家就餐问题解决死锁的三种思路。
管程
管程是管理进程间同步的机制,保证进程互斥的访问共享变量,并方便的阻塞、唤醒进程
管程是一种特殊的软件模块,有这些部分组成:
1.局部于管程的共享数据结构说明;
2.对该数据结构进行操作的一组过程;
3.对局部于管程的共享数据设置初始值的语句;
4.管程有一个名字。
管程的基本特征:
1.局部于管程的数据只能被局部于管程的过程所访问;
2.一个进程只有通过调用管程内的过程才能进入管程访问共享数据;
3.每次仅允许一个进程在管程内执行某个内部过程。
用管程解决生产者-消费者问题
Java中类似于管程的机制
总结
引入管程的目的无非就是要更方便地实现进程互斥和同步。
1.需要在管程中定义共享数据(如生产者消费者问题的缓冲区)
2.需要在管程中定义用于访问这些共享数据的“入口”―—其实就是一些函数(如生产者消费者问题中,可以定义一个函数用于将产品放入缓冲区,再定义一个函数用于从缓冲区取出产品)3.只有通过这些特定的“入口”才能访问共享数据
4..管程中有很多“入口”,但是每次只能开放其中一个“入口”,并且只能让一个进程或线程进入(如生产者消费者问题中,各进程需要互斥地访问共享缓冲区。管程的这种特性即可保证一个时间段内最多只会有一个进程在访问缓冲区。注意:这种互斥特性是由编译器负责实现的,程序员不用关心)
5.可在管程中设置条件变量及等待/唤醒操作以解决同步问题。可以让一个进程或线程在条件变量上等待(此时,该进程应先释放管程的使用权,也就是让出“入口”)﹔可以通过唤醒操作将等待在条件变量上的进程或线程唤醒。
程序员可以用某种特殊的语法定义一个管程(比如: monitor ProducerConsumer …..end monitor;),之后其他程序员就可以使用这个管程提供的特定“入口”很方便地使用实现进程同步/互斥了。