临界区资源互斥访问
进程管理中,对临界资源需要互斥访问。其中对实现对临界区互斥访问有软件和硬件方法。
- 软件方法包括:单标志发,双标志先检查法,双标志后检查法,皮特斯Peterson's算法。
- 硬件方法包括:中断屏蔽法,TSL指定和Swap指定。
但是四种软件实现方法,三种硬件实现方法都依然存在各种问题。最主要问题是都不能实现让权等待。
信号量
是一个变量,一个信号量对应一种资源,只能被两种PV两种原语操作,以此实现进程互斥,进程同步。(PV源于荷兰语proberen和verhogen分别是尝试试用和增加的意思)
补充:原语是一种特殊的程序段,不可被中断。原语是由关中断/开中断指令来实现的。
wait() //进入区
访问临界资源 //临界区
signal() //退出区
然后对于整型信号量种的pv操作原语wait和signal分别实现逻辑是:
wait(S){
while(S<=0);
S-=1; //检查和上锁都在wait中不能被中断(进程不能被切换走)
}
signal(S){
S+=1
}
对于记录型信号量:
image.png
typedef struct{
int value;
struct process *L;
} semaphore;
void wait (semaphore S) { //相当于申请资源
S.value--;
if(S.value<0) {
add this process to S.L;
block(S.L);
}
}
void signal (semaphore S) { //相当于释放资源
S.value++;
if(S.value<=0){
remove a process P from S.L;
wakeup(P);
}
}
image.png
信号量机制实现进程的同步,互斥,前驱关系
一个信号量对应一种资源
信号量的值=这种资源的剩余数量(若为负,说明此时有进程在等待这种资源)
1.进程的同步
一前一后的操作
同步量信号S,初始为0
在前操作之后执行V
在后操作之后执行P 口诀:前v后p
2.进程的互斥
如上pv操作
3.进程的前驱关系
本质上是多级同步问题
image.png
经典进程同步问题1-生产者消费者问题
缓冲区的这种临界资源只能互斥访问
p尝试消耗
v 增加
semaphore mutex=1;//互斥信号量,实现对缓冲区的互斥访问
semaphore empty=n; //同步信号量,表示空闲缓冲区的数量
semaphore ful1=0;//同步信号量,表示产品的数量,也即井空缓冲区的数量
producer(){
while(1){
生产一个产品;
P(empty);①
P(mutex);② //如果1 2 顺序颠倒呢,会出行死锁
把产品放入缓冲区;
V(mutex);
V(full)
}
}
image.png
所以实现互斥的p操作一定要在实现同步的P操作之后。
v操作不会导致进程阻塞,因此两个v操作顺序可以交换。
经典进程同步问题2-吸烟者问题
一个生产者 生产多类产品
经典进程同步问题3-读写者问题
缓冲区不会消耗掉
经典进程同步问题4-哲学家进餐问题
管程
封装思想