信号量机制
用户进程可以通过使用操作系统提供的一对原语来对信号量进行操作,从而很方便的实现了进程互斥、进程同步。
信号量其实就是一个变量(可以是一个整数,也可以是更复杂的记录型变量),可以用一个信号量来表示系统中某种资源的数量,比如:系统中只有一台打印机,就可以设置一个初值为1的信号量。
整形信号量
- 整形信号量与一般整形量不同,除初始化之外,仅能通过两个标准的原子操作wait(S)和signal(S)来访问,这两个操作也被称为P、V操作,用于实现系统资源的“申请”和“释放”。
- “检查”和“上锁”一气呵成,避免了并发、异步导致的问题。
-
- 不满足让权等待原则,会发生“忙等”。
- 不满足让权等待原则,会发生“忙等”。
记录型信号量
- 用S.value的初值表示系统中某种资源的数目。
- 对信号量S的一次P操作意味着进程请求一个单位的该类资源,因此S.value–,表示资源数减1,当S.value<0时表示该类资源已分配完毕,因此进程应调用block原语进行自我阻塞,主动放弃处理机,并插入该类资源的等待队列S.L中。
- 对信号量S的一次V操作意味着进程释放一个单位的该类资源,因此需要执行S.value++,表示该资源数加1,若加1后仍是S.value≤0,表示依然有进程在等待该类资源,因此应调用wakeup原语幻想等待队列中的第一个进程。
- 遵循了“让权等待”原则,不会出现“忙等”现象。
AND型信号量
(王道的课程中信号量机制只说了上述两种,这里的AND型信号量来自汤子瀛的计算机操作系统书本)
- ADN型信号量主要针对的是一个进程需要获取两个或更多的共享资源执行任务时的问题。
- 基本思想:对若干个临界资源的分配采取原子操作的方式:要么把它所请求的资源全部分配到进程,要么一个也不分配。为此,在wait中加入了一个“AND”条件,故称为AND同步,或称为同时wait操作,即Swait(Simultaneous wait)定义如下:
Swait(S1,S2,....,Sn)
{
while(true)
{
if(Si>=1 && ... && Sn>=1){
for(i=1;i<=n;i++)Si--;
break;
}
else{
//将进程放入第一个Si<1对应的i等待队列
//并且设置S1~Sn的资源数量为Swait()操作前的数量
}
}
}
Ssignal(S1,S2,...,Sn){
while(true){
for(i=1;i<=n;i++){
Si++;
//将所有Si等待队列内的进程放入就绪队列
}
}
}
信号量集
(王道的课程中信号量机制只说了上述两种,这里的信号量集来自汤子瀛的计算机操作系统书本)
- 信号量集主要针对的是执行进程时一次需要N个单位的某类临界资源的问题
- 对AND型信号量机制加以扩充,对进程所申请的所有资源以及每类资源不同的资源量需求,在一次P、V原语操作中完成申请或释放。
- 进程对信号量Si的测试值不再是1,而是该资源的分配下限ti,即要求
Si>=ti
。一旦允许分配,进程对该资源的需求值为di,即表示资源占用量,进行Si:=Si-di
的操作,对应的Swait和Ssignal格式为:
Swait(S1,t1,d1,...,Sn,tn,dn);
Ssignal(S1,d1,...,Sn,dn);
- Swait(S,d,d):此时信号量集中只有一个信号量S,但允许它每次申请d个资源,当现有资源数量少于d时,不予分配。
- Swait(S,1,1):此时信号量集已蜕化为一般的记录型信号量(S>1时)或互斥信号量(S=1)。
- Swait(S,1,0):当S>=1时,允许多个进程进入某特定区;当S变为0后,将阻止任何进程进入特定区,相当于一个可控开关。
整形信号量与记录型信号量
信号量的应用
信号量机制实现进程互斥
- 设置mutex为互斥信号量,初值为1,取值范围为(-1,0,1)。
当mutex = 1 时,表示两个进程皆未进入互斥的临界区
当mutex = 0 时,表示有一个进程进入临界区运行,另一个必须等待,挂入阻塞队列
当mutex = -1 时,表示有一个进程正在临界区运行,另外一个进程因等待而阻塞在信号量队列中,需要被当前已在临界区运行的进程退出时唤醒。 - P、V操作必须成对出现,缺少P(mutex)将会导致系统混乱,不能保证对临界资源的访问,缺少V(mutex)将会使临界资源永远不被释放,从而使因等待该资源而阻塞的进程永远不能被唤醒。
/*信号量机制实现互斥*/
semaphore mutex = 1; //初始化信号量
P1(){
while(1){
wait(mutex); //使用临界资源前需要加锁
//临界区;
signal(mutex); //使用临界资源后需要解锁
//剩余区;
}
}
P2(){
while(1){
wait(mutex);
//临界区;
signal(mutex);
//剩余区;
}
}
信号量机制实现进程同步
- 设置同步信号量S,初始为0
- 在“前操作”之后执行V(S)
- 在“后操作”之前执行P(S)
信号量机制实现前驱关系
每一对前驱关系都是一个进程同步问题
- 要为每一对前驱关系各设置一个同步变量
- 在“前操作”之后对相应的同步变量执行V操作
- 在“后操作”之前对相应的同步变量执行P操作
总结
考察多资源问题即为前面写到的AND型信号量和信号量集的相关问题