1. 信号量的定义与原语
信号量 :是一个被保护的变量,用于协调进程间的同步与互斥,只能通过两个原子操作访问:
- P操作(wait(S)):请求资源,若不可用则阻塞进程。
- V操作(signal(S)) :释放资源,若有等待进程则唤醒。
原语特性:操作不可中断(原子性),通过硬件或关中断实现。
2. 信号量的类型
(1)整型信号量
-
定义 :用整数
S
表示资源数量,初值为资源总数。 -
P操作:
wait(S) {
while (S <= 0);// 资源不足时忙等(不满足"让权等待")
S--;// 占用资源
} -
V操作:
signal(S) {
S++;// 释放资源
} -
缺点:忙等(CPU浪费),未实现"让权等待"准则。
(2)记录型信号量(解决忙等问题)
-
数据结构:
typedef struct {
int value;// 资源数量(初值=资源总数)
struct process *L;// 等待队列(阻塞进程链表)
} semaphore; -
P操作:
wait(semaphore *S) {
S->value--;// 请求资源
if (S->value < 0) {// 资源不足
add current process to S->L;// 阻塞当前进程,加入等待队列
block();// 放弃CPU(让权等待)
}
} -
V操作:
signal(semaphore *S) {
S->value++;// 释放资源
if (S->value <= 0) {// 仍有进程等待
remove a process P from S->L;// 从等待队列唤醒一个进程
wakeup(P);// 唤醒进程(阻塞→就绪)
}
} -
优点:通过阻塞/唤醒实现"让权等待",无忙等,是现代OS的标准信号量。
3. 信号量的应用
(1)实现互斥
目标:保证临界资源同一时间仅被一个进程访问。
步骤:
- 设置互斥信号量
S
,初值=1(表示资源可用)。 - 临界区前后分别执行
P(S)
(加锁)和V(S)
(解锁)。
示例:
semiapio s=1;
P1(){
...
P(S); //准备访问临界资源,加锁
进程P1的临界区;
V(S); //访问结束,解锁
...
}
P2(){
...
P(S); //准备访问临界资源,加锁
进程P2的临界区;
V(S) ; //访问结束,解锁
...
}
- 注意:
- 不同临界资源需独立信号量。
P(S)
和V(S)
必须成对出现(缺一导致死锁或永久阻塞)。
(2)实现同步
目标:协调进程执行次序(如"先生产后消费")。
步骤:
- 设置同步信号量
S
,初值=0(表示"资源未就绪")。 - 前驱进程 完成操作后执行
V(S)
(释放资源)。 - 后继进程 开始操作前执行
P(S)
(等待资源)。
-
示例(P1的x需在P2的y前执行):
semaphore S=0;//初始化信号量,初值为0
P1(){
x;//执行语句x
V(S);//告诉进程P2,语句x已经完成
...
}
P2(){
...
P(S);//检查语句x是否运行完成
y;//获得x的运行结果,执行语句y
...
}
(3)实现前驱关系
-
目标 :保证多个操作按固定顺序执行(如
S1→S2→S3
)。 -
方法 :为每对前驱关系设置同步信号量,初值=0。
-
前驱操作后
V(S)
,后继操作前P(S)
。 -
示例 (
S1→S2
,S1→S3
):semaphore a12=0, a13=0;// 前驱信号量
S1() { ...;
V(a12);
V(a13);
}// S1完成后唤醒S2、S3
S2() {
P(a12);
...; }// 等待S1后执行
S3() {
P(a13); ...; }// 等待S1后执行
4. 信号量操作的核心准则
- 互斥 :信号量初值=1,
P/V
夹临界区。 - 同步 :信号量初值=0,"生产者
V
,消费者P
"。 - 前驱关系 :每个依赖关系对应一个信号量,前驱
V
,后继P
。 - 原子性 :
P/V
操作不可中断,通过原语实现。
核心考点 📌
- 记录型信号量的
P/V
逻辑:
P(S)
:S.value--
,若S.value<0
则阻塞(加入等待队列)。V(S)
:S.value++
,若S.value<=0
则唤醒(等待队列非空)。
- 互斥vs同步的信号量初值:
- 互斥信号量初值=1(资源数=1)。
- 同步信号量初值=0(资源初始不可用)。
P/V
操作的顺序:
- 互斥:
P
(进入区)→临界区→V
(退出区)。 - 同步:前驱
V
→后继P
。
总结
信号量通过P/V
原语实现进程间的同步与互斥,记录型信号量解决了忙等问题,是操作系统中最核心的同步机制。理解其"请求-阻塞"和"释放-唤醒"逻辑,是解决复杂同步问题的基础。
✨ 一句话记忆 :互斥信号量初值1,P/V
夹临界区;同步信号量初值0,前驱V
来后继P
! ✨