它用于描述进程之间执行的先后顺序, DAG
进程(或程序)之间的前趋关系可用“→”来表示,如果进程Pi和Pj存在着前趋关系,可表示为Pi→Pj,表示在Pj开始执行之前Pi 必须完成。此时称Pi是Pj的直接前趋,而称Pj是Pi的直接后继
在前趋图中,把没有前趋的结点称为初始结点(Initial Node),把没有后继的结点称为终止 结点(Final Node),每个结点具有一个重量(Weight),用于表示该结点对应程序的执行时间。
对于具有下述四条语句的程序段:
S1: a :=x+2
S2: b :=y+4
S3: c :=a+b
S4: d :=c+b
可画出所示的前趋关系。可以看出:S3必须在a和b被赋值后方能执行;S4必 须在S3之后执行;但S1和S2则可以并发执行,因为它们彼此互不依赖。
并发的关键是你有处理多个任务的能力,不一定要同时。
并行的关键是你有同时处理多个任务的能力。
在多道程序环境下,程序的执行属于并发执行,此时它们将失去其封闭性,并具有间断性,以及其运行结果不可再现性的特征
为了能使程序并发执行,并且可以对并发执行的程序加以描述和控制,人们引入了“进程”的概念
(1) 进程是程序的一次执行。
(2) 进程是一个程序及其数据在处理机上顺序执行时所发生的活动。
(3) 进程是具有独立功能的程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单位
(1)进程是一个可拥有资源的独立单位
(2)进程同时又是一个可独立调度和分配的基本单位
• 进程控制块(PCB) : 用来描述进程的基本情况和活动过程
PCB作为进程实体的一部分,记录了操作系统所需要的,用于描述进程的当前情况以及管理进程运行的全部信息,是操作系统中最重要的记录型数据结构。
• 程序段
• 相关的数据段
PCB中还存放一些与进程调度和进程对换的信息。
进程状态:指明进程的当前状态,作为进程调度和对换的依据;
进程优先级:用于描述进程使用处理机的优先级别的一个整数,优先级高的进程应优先获得处理机;
进程调度所需的其它信息:与所采用的进程调度算法有关。
事件:指进程由执行状态转变为阻塞状态所等待发生的事件,即阻塞原因。
(1) 动态性。
(2) 并发性。
(3) 独立性。
(4) 异步性。
进程是动态的,程序是静态的。进程具有并发性,而程序没有。
进程是程序的一次执行。
(1) 就绪(Ready)状态。指进程已准备好运行,已分配到除CPU以外的所有资源(IO完成转为就绪)。
(2) 执行(Running)状态。 已获得CPU,正在执行。
(3) 阻塞(Block)状态。发生某事情(IO请求,申请缓冲区失败)导致无法继续执行
进程在运行过程中会经常发生状态的转换。 例如,处于就绪状态的进程,在调度程序为之分配了处理机之后便可执行,相应地,其状态就由就绪态转变为执行态;正在执行的进程(当前进程)如果 因分配给它的时间片已完而被剥夺处理机暂停执行时, 其状态便由执行转为就绪; 如果因发生某事件,致使当前进程的执行受阻(例如IO请求失败,申请缓冲区失败),使之无法继续执行,则该进程状态将由执行转变为阻塞
tips: CPU可以抽象理解为时间片
引入挂起操作的原因,是基于系统和用户的如下需要:
(1) 终端用户的需要。
(2) 父进程请求。
(3) 负荷调节的需要。
(4) 操作系统的需要。
当某进程被挂起, 意味着该进程处于静止状态. 如果该进程正在执行, 则暂停执行; 如果处于就绪状态, 则该进程暂不接受调度; 如果处于阻塞状态, 则静止阻塞.
与挂起操作对应的是激活操作
在引入挂起原语Suspend和激活原语Active后,在它们的作用下,进程将可能发生以下几种状态的转换:
(1) 活动就绪→静止就绪。
(2) 活动阻塞→静止阻塞。
(3) 静止就绪→活动就绪。
(4) 静止阻塞→活动阻塞。
(会画此图)
创建进程后,当系统当前资源允许时转为活动就绪,否则转为静止就绪
next: 进程的数据结构.
是进程管理中最基本的功能,主要包括创建进程,终止进程,阻塞进程等
进程控制一般是由OS 的内核中的原语来实现的
OS分为若干层,越是与硬件紧密相关的模块(如中断处理)越放在底层
OS内核包含了以下两大方面的功能
支撑功能,提供给OS其他众多模块需要的三种基础模块
1. 中断处理,内核最基本的功能
2. 时钟管理
3. 原语操作
资源管理功能
1. 进程管理
2. 存储器管理
3. 设备管理
处理机分为用户态和系统态两种运行状态
原语Create
在系统中每当出现了创建新进程的请求后,OS便调用进程创建原语Creat按下述步
骤创建一个新进程:
(1) 申请空白PCB,为新进程申请获得唯一的数字标识符,并从PCB集合中索取一
个空白PCB。
(2) 为新进程分配其运行所需的资源,包括各种物理和逻辑资源,如内存、文件、
I/O设备和CPU时间等。
(3) 初始化进程控制块(PCB)。
(4) 如果进程就绪队列能够接纳新进程,便将新进程插入就绪队列。
引起进程终止(Termination of Process)的事件
(1) 正常结束 (2) 异常结束 (3) 外界干预
原语destroy
原语block
阻塞是进程自身的一种主动行为
原语wakeup
wakeup执行的过程是:首先把被阻塞的进程从等待该事件的阻塞队列中移出,将其PCB中的现行状态由阻塞改为就绪,然后再将该PCB插入到就绪队列 中。
原语suspend
原语active
引入进程后有效提高系统利用率和吞吐量,但使得系统变得更为复杂
进程同步即为了对多个相关进程在执行次序上进行协调,使并发执行的诸进程之间能按照一定的规 则(或时序)共享系统资源,并能很好的相关合作,从而使程序的执行具有可再现 性。
1. 两种形式的制约关系
1) 间接相互制约关系 (如CPU,IO设备)
多个程序在并发执行时共享系统资源,导致其直接形成间接相互制约关系
2) 直接相互制约关系(如两个进程共享的缓冲区)
多个进程为完成同一项任务相互合作,其相互合作导致了他们直接的直接型制约关系
2. 临界资源(Critical Resouce) 在第一章中我们曾经介绍过,许多硬件资源如打印机、 磁带机等,都属于临界资源, 诸进程间应采取互斥方式,实现对这种资源的共享。
3. 临界区(critical section) 由前所述可知,不论是硬件临界资源还是软件临界资源,多个进程必须互斥地对它进行访问。把在每个进程中访问临界资源的那段代码称为临界区
目前许多计算机已提供了一些特殊的硬件指令,允许对一个字中的内容进行检测和修正,或者是对两个字的内容进行交换等。可利用这些特殊的指令来解决临界区问题。
1. 关中断
2. 利用Test-and-Set指令实现互斥
3. 利用Swap指令实现进程互斥
Dijkstra提出的一种很好的进程同步工具
最初由Dijkstra把整型信号量定义为一个用于表示资源数目的整型量S,它与一般整型量不同,除初始化外,仅能通过两个标准的原子操作 wait(S) 和signal(S)来访问。很长时间以来,这两个操作一直被分别称为P、V操作。
P意为通过,V表示增加,荷兰语
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200106104439756.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ExMDk3MzA0Nzkx,size_16,color_FFFFFF,t_70)
P操作实际物理意义:当S资源可用时即调用,否则阻塞当前进程
V操作实际物理意义:当S资源所在缓冲区未满时,释放S资源,否则阻塞当前进程
P,V操作为互斥操作时,他们处于同一进程;当P,V操作为同步操作时,不在同一进程中出现
在整型信号量机制中的wait操作,只要是信号量S≤0,就会不断地测试。因此,该机制并未遵循“让权等待”的准则,而是使进程处于“忙等”的状态。记录型信号量机 制则是一种不存在“忙等”现象的进程同步机制。但在采取了“让权等待”的策略后, 又会出现多个进程等待访问同一临界资源的情况。为此,在信号量机制中,除了需要一 个用于代表资源数目的整型变量value外,还应增加一个进程链表指针list,用于链接上 述的所有等待进程。
前面所述的进程互斥问题针对的是多个并发进程仅共享一个临界资源的情况。在有些应用场合,是一个进程往往需要获得两个或更多的共享资源后方能执行其任务。假定现有两个进程A和B,它们都要求访问共享数据D和E,当然,共享数据都应作为临界资 源。
在前面所述的记录型信号量机制中,wait(S)或signal(S)操作仅能对信号量施以加1或减1操作,意味着每次只能对某类临界资源进行一个单位的申请或释放。当一次需要N 个单位时,便要进行N次wait(S)操作,这显然是低效的,甚至会增加死锁的概率。此外, 在有些情况下,为确保系统的安全性,当所申请的资源数量低于某一下限值时,还必须 进行管制,不予以分配。因此,当进程申请某类临界资源时,在每次分配之前,都必须 测试资源的数量,判断是否大于可分配的下限值,决定是否予以分配。
利用信号量实现进程互斥
为使多个进程能互斥地访问某临界资源,只需为该资源设置一互斥信号量mutex,并设其初始值为1,取值范围为(-1, 0, 1),-1表示有一个进程正在临界区运行;0表示有一个进程进入临界区运行,另一个等待挂入阻塞队列;为1时表示都未进入临界区
然后将各进程访问该资源的临界区CS置于wait(mutex)和 signal(mutex)操作之间即可。
注意,wait(mutext)和signal(mutex)必须成对出现,缺少wait(mutext)则不能保证对临界资源的互斥访问,缺少signal(mutex)则会使得临界资源永远不被释放。
利用信号量实现前趋关系 还可利用信号量来描述程序或语句之间的前趋关系。设有两个并发执行的进程P1和P2。P1中有语句S1;P2中有语句S2。我们希望在S1执行后再执行S2。为实现这种前趋关 系,只需使进程P1和P2共享一个公用信号量S,并赋予其初值为0,将signal(S)操作放 在语句S1后面,而在S2语句前面插入wait(S)操作,即
在进程P1中,用S1;signal(S);
在进程P2中,用wait(S);S2;
由于S被初始化为0,这样,若P2先执行必定阻塞,只有在进程P1执行完S1; signal(S); 操作后使S增为1时,P2进程方能成功执行语句S2。
一群生产者进程在生产产品提供给消费者进程去消费,为使其并发执行,两者之间设置了一个具有缓冲区,生产者将产品放入缓冲区,消费者从缓冲区中取走。想办法使其之间保持同步。
int in = 0, out = 0; //当前生成/消费缓冲区下标
item buffer[n]; //n个缓冲区的缓冲池
semaphore mutext = 1, empty = n, full = 0; //空缓冲区和满缓冲区的数量
void proceducer(){
do{
producer an item nextp; 生产…
…
wait(empty);
wait(mutex);
buffer[in] = nextp;
in = (in+1)%n;
signal(mutext);
signal(full);
}while(TRUE);
}
void consumer(){
do{
wait(full);
wait(mutex);
nextc = buffer(out);
out = (out+1)%n;
signal(mutex);
signal(empty);
consumer an item nextc; 消费…
…
}while(TRUE);
}
producer();
consumer();
注意wait(mutex)和signal(mutex)和对full,empty的PV操作都必须成对出现,可以分别处于不同的程序中。
wait的顺序不能颠倒,先对wait full/empty再wait mutex,否则可能引起死锁
一个数据文件可被多个进程共享,Reader进程只读该文件,Writer进程只写该文件,允许多个进程同时读同一个对象,但不允许多个进程同时写或同时读写对象,因为会引起混乱。
wmutex防止Reader和Writer在读或写时互斥。readcount表示正在读的进程数目,只要>0便不允许Writer去写,因此只有当readcount==0时才执行wait(wmutex),表示尚无Readerr进程在读。因为readcount也是一个被多个Reader进程访问的临界资源,因此也为其设置一个互斥信号量rmutex
semaphore rmutex = 1, wmutex = 1;
int readcount = 0; //>0则不允许Reader去写
void reader(){
do{
wait(rmutex);
if(readcount==0) wait(wmutex);
readcount++;
signal(rmutex);
…
perform read operation;
…
wait(rmutex);
readcount--;
if(readcount==0) wait(wmutex);
signal(rmutex);
}while(TRUE);
}
void writer(){
do{
wait(wmutex);
…
perform write operation;
…
signal(wmutex);
}while(TRUE);
}
reader();
writer();
在操作系统中引入比进程更小的基本单位——线程,可以减少程序在并发执行时所付出的时空开销,使OS具有更好的并发性。
线程作为调度和分派的基本单位。
进程是独立调度和分配资源的基本单位,进程是调度和分派资源的基本单位
线程和进程都可以并发执行。
进程拥有资源,是系统中拥有资源的基本单位,线程本身不拥有资源,仅有一点能保证独立运行的资源。
同一进程中的不同线程之间的独立性要比不同进程直接的独立性低很多。
创建或撤销进程时线程的系统开销小。
多线程进程支持多处理机。