为什么要引进信号量机制?
用于解决互斥和同步的问题
同步:
直接制约关系,指的是为了完成某种合作的任务,这些进程需要调整他们的完成次序。让进程一前一后的进行
互斥:
间接制约关系,没有合作。当一个ji
只能使用两个标准的原语来访问:P,V操作(wait(),signal())
原语:
指完成某种指令不被分割和中断操作的指令序列,通常可以通过硬件来完成。
为什么不能被中断?
因为原语对变量的操作如果发生了中断,便有可能去运行另外一个对本变量的操作,会出现临界段的问题。
信号量,顾名思义,就是起着一个发信号的作用。
信号量机制的分类
1、整型信号量
定义为一个用于表示资源数目的整型数S
wait(){
while(S<=0);//当该资源的数量小于等于0时,说明没得分配了,会在这里阻塞
S=S-1;//当资源的数量>0时,说明该资源被空闲出来,可以进行申请
//申请了就需要对当前资源数量--
}
signal(){
S=S+1;
}
但是这一机制没有遵循“让权等待”原则,因为如果当前资源不能使用,会一直阻塞在“while(S<=0)”这一步,却始终占用着处理机
2、记录性信号量
typedef struct{
int value;//用于存储剩余的资源数
struct process*L;//用于放置被挂起的进程
}semaphore;
wait(S){//一次P操作,申请资源
S.value--;
if(S.value<0){//如果该进程申请了以后发现资源数少于0,说明没得资源给他了
add this process to S.L;//他将会被挂起,放在S.L的队列里面;
}
}
signal(S){
S.value++;//如果当前有进程释放了资源,那么资源数量++
if(S.value<=0){//但如果当前value还是小于等于0,说明之前还有要申请的,还在排队的进程
remove p from S.L;
wakeup(p);//所以需要将S.L队头的元素唤醒
}
}
信号量机制的使用
1、利用信号量实现同步
semaphore S=0; //设置同步初始值为1
P1(){
X;V(S); //Y的计算需要使用X的值,所以在限制性的X后面加上V操作
}
P2(){
P(S);Y; //Y后执行,所以在Y前面加上P操作
}
先V后P
先执行的操作执行完,V了一次以后S=1(因为V操作里面要value++),之后再运行到P时,P操作里面会对value先进行一次--,此时value==0,value>0,不会被阻塞,才执行后面的Y。
V相当于,前面的操作做完了给后面的操作发通知;在后面要执行的操作执行之前,先P一下,检查一下前面有没有通知他干活。
2、信号量实现进程互斥(互斥特性由浏览器负责实现,对于不同的临界资源会有不同的信号量初值)
semaphore S=1;//设置可用的资源数为1,初始值为1
P1(){ P(S); 临界区 V(S); }
P,V夹紧临界区
当P1运行,首先value--,value==0,如果这时候又有别的资源想要访问临界区,则也会先执行一个P,value--,value==-1,value<0会被阻塞在这里,不会往下执行,也就不会进入临界区。P1退出临界区以后执行一个V操作,释放资源,并且唤醒刚才被阻塞的进程。
3、利用信号量实现前驱关系