信号量
什么是信号量
相信课上大家已经对信号量有了一定的了解(没听课的找网课复习一下),这里再介绍一下信号量.
信号量是一种抽象数据类型,由一个整型(sem)变量和两个原子操作组成;
P(sem)
(Prolaag,荷兰语尝试减少)
sem减1
如sem<0,进入等待,否则继续
V(sem)
(Verhoog,荷兰语增加)
sem加1
如sem<=0,唤醒一个等待进程
可以这样理解,一群人在吃苹果,服务员会提供苹果。如果某个人对一个信号量执行一个P操作,就是尝试获取一个苹果,那么如果发现苹果不够了,就趴着冬眠;而服务员对一个信号量进行一个V操作,就相当于在桌子上放一个苹果,如果发现有人在冬眠中等待苹果,就叫醒一个人。而sem的初始值,实际上可以理解成桌子上初始的苹果数量。
信号量的实现(伪代码):
class Semaphore {
int sem;
WaitQueue q;
}
Semaphore::P(){
sem--;//消耗一个苹果
if(sem < 0){//不够了
Add this thread t to q;
block(t)
}
}
Semaphore::V(){
sem++;//添加一个苹果
if(sem <= 0){//发现有人在冬眠等苹果
Remove a thread t from q;
wakeup(t);
}
}+
信号量的一些应用
临界区互斥访问
我们可以利用信号量实现一把锁(相信你们学过),用来互斥访问临界区
把信号量的初值设置为1,相当于一把锁,谁得到了就可以进入临界区,得不到的就要等待。然后那个有锁的人,用V操作释放这把锁,其他人才能得到它。
mutex = new Semaphore(1);
mutex->P();//lock(&lk),获取
Critical Section;
mutex->V();//unlock(&lk),释放
这里要注意必须成对使用P()
操作和V()
操作:
P()
操作保证互斥访问临界资源V()
操作在使用后释放临界资源PV
操作不能次序错误、重复或遗漏
用信号量实现条件同步
条件同步设置一个信号量,其初值为0
condition = new Semaphore(0);
下面是A和B线程的一些执行序列:
thread A thread B
... M ...
... N ... ... X ...
... Y ...
我们可以看到A
有M
和N
模块,B
有X
和Y
模块,这里为了保证B
执行到X
后,A
才能执行N
,可以使用信号量实现条件同步。其中在N执行前进行P操作,然后A进入等待,B执行完X后,使用V操作唤醒A。
thread A thread B
... M ...
condition->P(); -----------+
... N ... | ... X ...
+---------> condition->V();
... Y ...
Last updated