操作系统——同步与互斥
目录
1.同步与互斥的概念
1.1临界资源
1.2同步
1.3互斥
2.实现临界区互斥的基本方法
2.1软件实现方法
1)单标志法
2)双标志先检查法
3)双标志后检查法
4)Peterson 算法
2.2硬件实现方法
1)中断屏蔽方法
2)硬件指令方法—TestAndSet指令
3)硬件指令方法—Swap指令
3.互斥锁
1.同步与互斥的概念
虽然多个进程可以共享系统中的各种资源,但其中许多资源一次只能为一个进程所用,一次仅允许一个进程使用的资源称为临界资源,许多物理设备都属于临界资源,如打印机等。此外,还有许多变量、数据等都可以被若干进程共享,也属于临界资源。
1.1临界资源
对临界资源的访问,必须互斥地进行,在每个进程中,访问临界资源的那段代码称临界区,为了保证临界资源的正确使用,可将临界资源的访问过程分成4个部分:
1)进入区。为了进入临界区使用临界资源,在进入区要检查可否进入临界区,若能进入临界区,则应设置正在访问临界区的标志,以阻止其他进程同时进入临界区。 2)临界区。进程中访问临界资源的那段代码,又称临界段。
3)退出区。将正在访问临界区的标志清除。
4)剩余区。代码中的其余部分。
1.2同步
同步亦称直接制约关系,是指为完成某种任务而建立的两个或多个进程,这些进程因为需要协调它们的运行次序而等待、传递信息所产生的制约关系。
例如,输入进程A通过单缓冲向进程B提供数据。当该缓冲区空时,进程B不能获得所需数据而阻塞,一旦进程 A 将数据送入缓冲区,进程B就被唤醒。反之,当缓冲区满时,进程 A被阻塞,仅当进程B取走缓冲数据时,才唤醒进程A。
1.3互斥
互斥也称间接制约关系。当一个进程进入临界区使用临界资源时,另一个进程必须等待,当占用临界资源的进程退出临界区后,另一进程才允许去访问此临界资源。
例如,在仅有一台打印机的系统中,有两个进程A和进程B,若当进程A需要打印时,系统已将打印机分配给进程B,则进程A必须阻塞。一旦进程B将打印机释放,系统便将进程A唤醒,并将其由阻塞态变为就绪态。
实现临界区互斥必须遵循的准则
1)空闲让进。临界区空闲时,可以允许一个请求进入临界区的进程立即进入临界区。
2)忙则等待。当已有进程进入临界区时,其他试图进入临界区的进程必须等待。
3)有限等待。对请求访问的进程,应保证能在有限时间内进入临界区,防止进程无限等待。
2.实现临界区互斥的基本方法
2.1软件实现方法
1)单标志法
该算法设置一个公用整型变量turn,指示允许进入临界区的进程编号,当turn=0时,表示允许P0进入临界区;当turn=1时,表示允许P1,进入临界区。即可以使用while关键字实现。
while(turn!=0);
while(turn!=1);
2)双标志先检查法
该算法设置一个布尔型数组 flag[2],用来标记各个进程想进入临界区的意愿,flag[i]=true 表示Pi想要进入临界区(i=0或1)。Pi进入临界区前,先检查对方是否想进入临界区,若想,则等待;否则,将 flag[i]置为true后,再进入临界区;当Pi退出临界区时,将flag[i]置为false。
//进程 P0:
while(flag[1]);//进入区
flag[0]=true;//进入区
critical section;//临界区
flag[0]=false;//退出区
remainder section;//剩余区
//进程 P1:
while(flag[0]);//进入区
flag[1]=true;//进入区
critical section;//临界区
flag[1]=false;//退出区
remainder section;//剩余区
3)双标志后检查法
算法二(双标志先检查法)先检查对方的标志,再设置自己的标志,但这两个操作又无法一气呵成,于是使得两个进程同时进入临界区的问题。因此,想到先设置后检查法,以避免上述问题。算法三先设置自己的标志,再检查对方的标志,若对方的标志为tue,则等待;否则,进入临界区。
//进程 P0:
flag[0]=true;//进入区
while(flag[1]);//进入区
critical section;//临界区
flag[0]=false;//退出区
remainder section;//剩余区
//进程 P1:
flag[1]=true;//进入区
while(flag[0]);//进入区
critical section;//临界区
flag[1]=false;//退出区
remainder section;//剩余区
4)Peterson 算法
Peterson 算法结合了算法一和算法三的思想,利用 flag[]解决互斥访问问题,而利用 turn 解决“饥饿”问题。若双方都争着进入临界区,则可让进程将进入临界区的机会谦让给对方。也就是说,在每个进程进入临界区之前,先设置自己的flag标志,再设置允许进入turn 标志;之后,再同时检测对方的 flag 和 turn 标志,以保证双方同时要求进入临界区时,只允许一个进程进入。
//进程 P0:
flag[0]=true;//进入区
turn=1;//进入区
while(flag[1] && turn==1);//进入区
critical section;//临界区
flag[0]=false;//退出区
remainder section;//剩余区
//进程 P1:
flag[1]=true;//进入区
turn=0;//进入区
while(flag[0] && turn==0);//进入区
critical section;//临界区
flag[1]=false;//退出区
remainder section;//剩余区
2.2硬件实现方法
1)中断屏蔽方法
当一个进程正在执行它的临界区代码时,防止其他进程进入其临界区的最简单方法是关中断。因为CPU只在发生中断时引起进程切换,因此屏蔽中断能够保证当前运行的进程让临界区代码顺利地执行完,进而保证互斥的正确实现,然后执行开中断。
2)硬件指令方法—TestAndSet指令
借助一条硬件指令—TestAndSet 指令(简称 TS 指令)实现互斥,这条指令是原子操作。其功能是读出指定标志后将该标志设置为真。
boolean TestAndSet(boolean *lock){
boolean old;
old=*lock;//old 用来存放 lock 的旧值
*1ock=true;//无论之前是否已加锁,都将lock置为 true
return old;//返回 lock 的旧值
}
3)硬件指令方法—Swap指令
Swap 指令的功能是交换两个字(字节)的内容。
Swap(boolean *a,boolean *b){
boolean temp=*a;
*a=*b;
*b=temp;}
3.互斥锁
解决临界区最简单的工具就是互斥锁(mutex lock)。一个进程在进入临界区时调用 acquie()函数,以获得锁;在退出临界区时调用release()函数,以释放锁。每个互斥锁有一个布尔变量available,表示锁是否可用。如果锁是可用的,调用 acquire()会成功,且锁不再可用。当一个进程试图获取不可用的锁时,会被阻塞,直到锁被释放。
acquire(){//获得锁的定义
while(!available);
//忙等待
available=false;//获得锁}
release(){//释放锁的定义available=true;//释放锁
}
acquire()或release()的执行必须是原子操作,因此互斥锁通常采用硬件机制来实现。