OS

您所在的位置:网站首页 信号量的同步与互斥 OS

OS

2024-07-13 23:12| 来源: 网络整理| 查看: 265

在上一篇笔记中,我们介绍到了进程同步和进程互斥,以及用软件层面上的四种方法、硬件层面上的三种方法,分别实现进程互斥。但是这些方法大部分都存在着一些问题:

“上锁”与“检查”是非原子操作都无法做到“让权等待”

接下来,我们介绍一种全新的信号量机制。

1. 信号量机制

信号量机制可以让用户通过使用操作系统提供的一对原语来对信号量进行操作,从而方便地实现进程互斥和进程同步。信号量(Semaphore)其实就是一个变量,它可以记录系统中某个资源的数量,而原语指的是 wait(S) 原语和 signal(S) 原语(或者说是 P 操作和 V 操作),可以看作是两个函数。

1.1 整型信号量

信号量如果单纯是一个整数型的变量,那么就称为整型信号量,它的值记录了系统中某种资源的数量。在使用整型信号量的情况下,P 、V 操作是类似这样的:

代码语言:javascript复制int S = 1; wait(int S) { while(S ”后操作“始终无法执行

所以,在这种情况下,就只能转而执行 V 所在的进程了。在这个进程里,由于 V 在”前操作“后面,所以一定是”前操作“执行完了再去执行 V。而执行 V 就会自增信号量,同时唤醒对方进程,对方进程再去顺序执行 P 操作 —— 虽然此时信号量又自减,但是是在加一的基础上自减,所以并不会导致再次阻塞,所以 P 执行完后就顺序执行”后操作“。由此,我们确保了两个操作一定是严格按照先后顺序执行的。

来看下面的例子:

代码语言:javascript复制// 顺序应该是:code1,code2,code4 P0: P1: code 1 P(S) code 2 code 4 V(S) code 5 code 3 code 6

我们设想比较差的情况 —— P1 拼命想要抢先执行 code 4,看看会发生什么。假设是 P1 首先占用处理机,那么就会执行 P 操作,这个操作使得信号量由 0 变成 -1,进而进入 if 代码块,使得 P1 进程阻塞;这之后,处理机来到 P0,执行 code1,code2,V 操作,使得信号量由 -1 变成 1,同时唤醒 P1 进程;P1 进程使得信号量由 1 变成 0,但是不满足 if 条件,所以不会阻塞自己,而是正常往下执行,来到 code4。以上,整个过程确保了按照 code1,code2,code4 的顺序执行。

2.3 信号量实现进程前驱关系

前面描述的都是两个进程的同步问题,但有时候也可能出现像下图这样多个进程互相依赖、有序运行的情况。其中,code * 语句仍然是前操作或者后操作,P1 进程有 code1 语句,P2 进程有 code2 语句…… 以此类推,这里要求六个进程必须按照箭头所指方向有序运行。

其实这种情况就是把多个同步问题结合起来,对于每一对前驱关系来说,都有属于本关系的信号量,所以我们仍然是可以用信号量机制来实现的。代码大概如下:

代码语言:javascript复制P1: P2: P3: P4: code1 P(signal1) P(signal2) P(signal3) V(signal1) code2 code3 code4 V(signal2) V(signal3) V(signal7) V(signal5) V(signal4) P5: P6: P(signal4) P(signal5) code5 P(signal6) V(signal6) P(signal7) code6

可以观察到,除了 P1 进程之外,其它进程首先执行的都是 P 操作,所以一旦这些进程之一首先拿到处理机使用权,都无一例外地会进入阻塞队列。由于情况很多,这里我们试着只分析某一种情况 ——

假设一开始是 P2 占有处理机,那么由于 signal1 初始为 0,导致了 P2 进队列,此后处理机来到 P3,P3 同样进队列……. 以此类推,阻塞队列就会变成:

随后总算来到 P1 进程了,P1 进程作为一切的开始,特殊之处就在于它不是以 P 操作开始的,P1 会首先执行 V(signal1),这一步把 signal1 加一,同时唤醒 P2 进程,P2 进程进入就绪队列:

再之后,P1 执行 V(signal2),这一步把 signal2 加一,同时唤醒 P3 进程,P3 进程也进入就绪队列。

P1 执行完之后,就绪队列队头的 P2 进入运行态,执行到 V(signal3) 的时候,signal3 加一,同时唤醒 P4 进程,P4 进程进入就绪队列,

再之后,P2 执行 V(signal4),这一步把 signal4 加一,同时唤醒 P5 进程,P5 进程也进入就绪队列。

P2 执行完之后,处理机调度就绪队列队头的 P3 开始执行,P3 执行到 V(signal7) 的时候,signal7 加一,注意这一步没有唤醒任何进程

P3 执行完之后,处理机调度就绪队列队头的 P4 开始执行,P4 执行到 V(signal5) 的时候,signal5 加一,同时唤醒 P6 进程,P6 进程进入就绪队列

P4 执行完之后,处理机调度就绪队列队头的 P5 开始执行,P5 执行到 V(signal6) 的时候,signal6 加一,注意这一步没有唤醒任何进程(阻塞队列已经没有进程了)

P5 执行完之后,处理机调度就绪队列队头的 P6 开始执行,P6 的 signal6 、signal7 在前面已经得到加一操作,所以此时绝对不会在这里卡住,可以顺利执行,直到结束。

这样基本就把整个流程过了一遍,当然,经过排列组合之后,是有很多情况的,但是分析过程都是大同小异的。

3. 信号量集机制

前面所说的信号量机制都属于多个进程申请同一个资源的情况,如果是多个进程申请多个资源,那么就需要用到信号量集机制了。信号量集机制包括 AND 信号量集机制和一般信号量集机制,它的核心是为每一个资源分配一个信号量,在某个进程申请多个资源的时候,要么全部资源同时都分配给它,要么全部资源一个也不分配给它。与信号量机制使用的 wait 和 signal 不同,信号量集机制使用的是 Swait 和 Ssignal (S 表示 Simultaneous,同时的),并且在具体实现上的思路也有所不同。

3.1 AND 信号量集机制

AND 信号量集机制的 PV 操作如下:

代码语言:javascript复制Swait(S1,S2,...,Sn) { if(S1>=1 && S2>=1 &&...&& Sn>=1) // 注意这里是先检查后分配 for (i=1;i=t1 && S2>=t2 &&...&& Sn>=tn) for (i=1;i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3