(王道408考研操作系统)第二章进程管理-第三节4:信号量机制(整型记录型信号量和PV操作)
Posted 我擦了DJ
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(王道408考研操作系统)第二章进程管理-第三节4:信号量机制(整型记录型信号量和PV操作)相关的知识,希望对你有一定的参考价值。
可以看出,不管是进程互斥的软件实现方法还是硬件实现方法,他们都无法解决“让权等待”这个问题,也即处理会处于会处于忙等状态。
而信号量则是一种功能较强的机制,可以有效的互斥与同步的问题
一:信号量是什么
信号量:本质就是一个变量(分为整形和记录型两种),表示系统中某种资源的数量。控制信号量有两种原子操作:
- P操作(wait(S)原语):这个操作会把信号量减去1,相减后如果信号量<0则表示资源已经被占用,进程需要阻塞;相减后如果信号量 ≥ 0 \\ge0 ≥0,则表明还有资源可以使用,进程可以正常执行
- V操作(signal(S)原语):这个操作会把信号量加上1,相加后如果信号量 ≤ 0 \\le0 ≤0,则表明当前有阻塞中的进程,于是会把该进程唤醒;相加后如果信号量>0,则表明当前没有阻塞中的进程
二:整型信号量
整型信号量:使用一个整型变量作为信号量,用来表示系统中某种资源的数量。比如某种资源S初始为1
int S=1;//初始信号量,表示当前系统中可用资源数
void wait(int S){//wait原语相当于进入区
while(S<=0);//如果资源数不够,就一直循环等待
S=S-1;//如果资源数够,就占用一个资源
}
void signal(int S){//signal原语,相当远退出区
S=S+1;//使用完资源后释放资源,也即归还
}
具体描述:有如下进程
- 对于进程 P 0 P_{0} P0,它想要使用资源S,必须先进行P操作。此时由于S=1,所以不会被卡住,然后资源数减一,S=0
- 此时产生了进程切换,对于 P 1 P_{1} P1它也想要使用资源S,,必须先进行 P P P操作。不过此时S=0,所以 P 1 P_{1} P1它会被卡在循环那里,直到P_{0}进程释放资源
- 其他进程也和 P 2 P_{2} P2一样
- P 0 P_{0} P0进程执行完临界区代码后,在退出区执行V操作,归还资源,此时S=1
- 由于 P 0 P_{0} P0释放了资源,所以 P 1 P_{1} P1进程此时从卡住的地方脱离开来继续向下进行P操作。后续进程亦是如此
缺陷:不满足让权等待,会发生忙等
三:记录型信号量
记录型信号量:除了需要使用一个用于代表资源数目的整形变量value
外,还需要增加一个进程链表L,用于链接所有等待该资源的进程,使用一个指针指向。其用于记录的数据结构为:
typedef struct
{
int value;//剩余资源数目
struct process* L;//等待队列
}semaphore;
对应P操作和V操作
1:某进程需要使用资源时,需要进行P操作
void wait(semaphore S)
{
S.value--;
if(S.value < 0)
{
block(S.L);
}
}
- 执行了P操作,资源数量减一
- 然后进行判断,如果<0那么表示没有系统资源了,所以是没有办法分配给当前申请该种资源的进程的,所以使用block原语使进程从运行态进入阻塞态,并将其挂到信号量为S的阻塞队列中
2:某进程需要使用完资源时,需要进行V操作
void signal(semaphore S)
{
S.value++;
if(S.value<=0)
{
wakeup(S.L);
]
}
- 执行了V操作,资源数量加一
- 然后进行判断,如果<=0表示还有进程在等待这种资源,所以使用wakeup原语唤醒等待队列中的一个进程,该进程从阻塞态变为就绪态,并把它所等待的资源分配给它
具体描述:假设有2个系统资源,初始化时将信号量S的S.value
设置为2,S.L
设置为NULL,并有如下进程,它们都想要这种资源
- 对于
P
0
P_{0}
P0进程,执行完P操作后,
S.value=1
, P 0 P_{0} P0开始使用该资源 - 切换到
P
1
P_{1}
P1进程,执行完P操作后,
S.value=0
, P 1 P_{1} P1开始使用该资源 - 切换到
P
2
P_{2}
P2进程,执行完P操作后,
S.value=-1
,此时满足S.value<0
,表示系统中没有多余资源可以分配,所以 P 2 P_{2} P2执行block
原语, P 2 P_{2} P2被挂到等待队列中 - 切换到
P
3
P_{3}
P3进程,执行完P操作后,
S.value=-2
,此时满足S.value<0
,表示系统中没有多余资源可以分配,所以 P 3 P_{3} P3执行block
原语, P 3 P_{3} P3被挂到等待队列中 - P 2 P_{2} P2和 P 3 P_{3} P3目前都不可以进行服务
- 此时切换到
P
0
P_{0}
P0进程,执行完V操作后,
S.value=-1
,此时满足S.value<=0
,表示等待队列中依然还有进程在等待资源,所以 P 0 P_{0} P0进程执行wakeup
原语,唤醒 P 2 P_{2} P2进程(因为 P 2 P_{2} P2此时在等待队列队头), P 2 P_{2} P2由阻塞态转为就绪态,同时刚刚 P 0 P_{0} P0释放的资源会分配给 P 2 P_{2} P2 -
P
0
P_{0}
P0在执行完毕之后,假如CPU继续再向
P
2
P_{2}
P2服务,
P
2
P_{2}
P2开始使用资源,使用完毕之后,执行V操作,
S.value=0
,此时满足S.value<=0
,表示等待队列中依然还有进程在等待资源,再利用wakeup
原语唤醒 P 3 P_{3} P3, P 2 P_{2} P2释放的资源会分配给 P 3 P_{3} P3,等待队列为空 -
P
2
P_{2}
P2在执行完毕之后,CPU为
P
1
P_{1}
P1服务,执行V操作,
S.value=1
,此时不满足S.value<=0
,表示等待队列中没有进程在等待资源,因此 P 1 P_{1} P1无需执行wakeup
原语 - 最后是
P
3
P_{3}
P3,执行V操作,
S.value=2
, P 3 P_{3} P3结束
记录型信号量优点(总结):
S.value
的初值表示系统中某种资源的数目;S.value
如果为正表示目前系统中该资源还有剩余;S.value
如果为负,那么其绝对值表示在等待队列中等待该资源的进程数目
- P操作: 对信号量S的一次P操作意味着进程请求一个单位的该类资源,所以
S.value--
,表示资源数目少1。当S.value<0
时表示该类资源已经分配完毕,因此进程应该调用block
原语进行自我阻塞,主动放弃处理机,并插入到该类资源的等待队列S.L
中。所以该机制遵循了让权等待原则,不会出现忙等现象 - V操作: 对信号量S的一次V操作意味着进程释放一个单位的该类资源,所以
S.value++
,表示资源数目多1。如果加1之后仍然有S.value<=0
,表示依然有进程在等待该类资源,因此应该调用wakeup
原语唤醒等待队列中的第一个进程
以上是关于(王道408考研操作系统)第二章进程管理-第三节4:信号量机制(整型记录型信号量和PV操作)的主要内容,如果未能解决你的问题,请参考以下文章
(王道408考研操作系统)第二章进程管理-第三节8:经典同步问题之吸烟者问题
(王道408考研操作系统)第二章进程管理-第三节1:进程同步
(王道408考研操作系统)第二章进程管理-第三节7:经典同步问题之多生产者与多消费者问题
(王道408考研操作系统)第二章进程管理-第三节3:实现进程互斥的硬件方法