信号量机制
1.整形信号量
一个整数值,表示空闲资源总数,除初始化外,仅能通过两个标准的原子操作来访问,这两个操作为wait(s)和signal(s)。
其操作可被描述为:
P(s): Wait(s): while ( s<=0 ) ;
s - - ;
V(s): Singal(s): s + + ;
2.记录型信号量
采用了记录型的数据结构,其数据结构如下:
typedef struct Semaphore{
int value; //其初值表示系统中每类资源的数目
process_list * list; //阻塞的进程队列
} semaphore ;
当s—>value的值为负数时,表示该类资源已经分配完,因此进程应该调用block原语进行自我阻塞,插入到信号量链表中,当s—>value的值加1后,将使用wakeup 语句将第一个进程唤醒。
若s—>value的初始值为1,此时信号量互斥,进程互斥。
3.AND型信号量
将一段代码同时需要的多个临界资源,采用原子方式,要么全分配给它,要么一个都不分配。因为这样,在wait操作中增加了一个“AND”条件,称为同时wait操作,即Swait(Simultaneous Wait)。同样地,使用结束后一起释放,称为Ssignal;
Swait:同时满足条件时,一起调用所有资源
Swait(S1, S2, …, Sn) //P原语;
{
if (S1 ≥1 and S2 ≥ 1 … Sn ≥ 1) //满足资源要求时;
{
for (i = 1; i <= n; ++i)
Si - - ; // 保证可满足资源要求时,进行减1操作
}
else //某些资源不够时的处理
{
阻塞调用进程;
}
}
Ssignal:待进程使用完,同时释放所有的资源
Ssignal(S1, S2, …, Sn){
while ( TRUE )
for (i = 1; i <= n; ++i){
si++ ;
} }
4.信号量集
在AND型信号量集的基础上进行扩充,扩充为进程需要申请多个资源,每个资源可能申请多个的情况。
每个资源对应一个信号量Si,进程对资源i的需求值为di,每次申请或释放di个,Si=Si-di和Si=Si+di;资源i的测试值为ti,当资源个数小于ti时,便不再分配。
一般“信号量集”的几种特定情况:
Swait(S, d, d):每次申请d个资源,当少于d个时,不分配
Swait(S, 1, 1):互斥信号量;
Swait(S, 1, 0):
相当于一个可控开关,不申请资源
S>=1 : 允许多个进程进入某特定区;
S=0 : 禁止任何进程进入某特定区;
5.利用信号量实现进程互斥
semaphore mutex =1; //mutex为互斥信号量,初值为1
PA(){
while(1){
wait(mutex);
临界区; 必须成对使用,不能次序错误
signal(mutex);
剩余区;
}
}
mutex=1 :两个进程皆未进入互斥的临界区
mutex=0 :一个进程正在运行,另一个等待,挂入阻塞队列
mutex=-1 :一个进程在运行,另外一个在信号量队伍中,需要该进程退出后唤醒
6.信号量表示前趋关系
• 前趋关系:并发执行的进程P1和P2中,分别有代码C1和C2,要求C1在C2开始前完成;
代码框架可表示为:
P1(){S1; signal (S);}
P2(){ wait(S);S2; }
更多的前趋关系,均类似于此。