操作系统目录:
第 1 章 计算机系统概述
进程管理(2~4)
第 2 章 进程与线程
第 3 章 处理机调度
第 4 章 进程同步与死锁
第 5 章 内存管理
第 6 章 文件管理
第 7 章 I/O管理
文章目录
1. 进程同步、进程互斥
- 什么是进程同步
并发执行两个进程时,现在要求一号指令必须在二号指令之前执行。例如写数据必须发生在读数据之前。
并发性带来了异步性,有时需要通过进程同步解决这种异步问题。有的进程之间需要相互配合地完成工作,各进程的工作推进需要遵循一定的先后顺序。
2. 什么是进行互斥
临界资源:一个时间段内只允许一个进程使用的资源。
对临界资源的访问,需要互斥的进行。即同一时间段内只能允许一个进程访问该资源。
3. 对临界资源的互斥访问,可以分为如下四个部分:
do {
entry section; //进入区:检查是否可进入临界区,若可进入,需要“上锁”
critical section; //临界区:访问临界资源的那段代码
exit section; //退出区:负责“解锁”
remainder section; //剩余区:做其他处理
} while(true)
- 对临界资源的互斥访问,遵循以下原则:
- 空闲让进:临界区空闲时,应允许一个进程访问
- 忙则等待:临界区正在被访问时,其他试图访问的进程需要等待
- 有限等待:要在有限时间内进入临界区,保证不会饥饿
- 让权等待:进不了临界区的进程,要释放处理机,防止进程忙等待
2. 进程互斥的软件实现方法
- 单标志法
每个进程进入临界区的权限只能被另一个进程赋予
在进入区只做“检查”,不“上锁”
在退出区,把临界区的使用权转交给另一个进程(相当于在退出区给另一个进程“解锁”,给自己“上锁”)
int turn = 0; //turn 表示当前允许进入临界区的进程号
P0进程:
while (turn != 0); //1⃣️进入区
critical section; //2⃣️临界区
turn = 1; //3⃣️退出区
remainder section; //4⃣️剩余区
P1进程:
while( turn != 1); //5⃣️进入区
critical section; //6⃣️临界区
turn = 0; //7⃣️退出区
remainder section; //8⃣️剩余区
turn
的初值为0
,即刚开始只允许0
号进程进入临界区。- 若
P1
先上处理机运行,则会一直卡在5⃣️(因为while的循环条件一直被满足)。直到P1
的时间片用完,发生调度,切换P0上处理机。 P0
进程,因为while
循环条件不被满足,所以会跳出循环,进入临界区,P0
可以正常访问临界区。- 在
P0
访问临界区期间即使切换回P1
,P1
依然会卡在5⃣️(因为turn没有变) - 只有
P0
在退出区将turn
改为1
后,P1
才能进入临界区。
问题:不遵循“空闲让进”
- 双标执先检查
在进入区先“检查”后上锁,退出区“解锁”
bool flag[2]; //表示进入临界区意愿的数组
flag[0] = false;
flag[1] = false;//刚开始设置为两个进程都不想进入临界区
P0 进程:
while (flag[1]);
flag[0] = true;
critical section;
flag[0] = false;
remainder section;
P1 进程:
while (flag[0]); //如果此时P0想进入临界区,P1就一直循环等待
flag[1] = true; //标记为 P1 进程想要进入临界区
critical section; //访问临界区
flag[1] = false; //访问完临界区,修改标记为 P1 为不想使用临界区
remainder section;
问题:不遵循“忙则等待”
3. 双标志后检查法
在进入区,先“上锁”后“检查”,退出区“解锁”
bool flag[2]; //表示进入临界区意愿的数组
flag[0] = false;
flag[1] = false; //刚开始设置为两个进程都不想进入临界区
P0 进程:
flag[0] = true;
while (flag[1]);
critical section;
flag[0] = false;
remainder section;
P1 进程:
flag[1] = true; //标记为 P1 进程想要进入临界区
while (flag[0]); //如果P0也想进入临界区,则P1循环等待
critical section; //访问临界区
flag[1] = false; //访问完临界区,修改标记为 P1 不想使用临界区
remainder section;
问题:不遵循“空闲让进、有限等待原则”,可能导致饥饿
4. Peterson算法
在进入区“主动争取—主动谦让—检查对方是否想进、自己是否谦让”
bool flag[2];
int turn = 0;
P0 进程:
flag[0] = true;
turn = 1;
while (flag[1] && turn==1)
//进入区
critical section;
flag[0] = false;
remainder section;
P1进程:
flag[1] = true; //表示自己想进入临界区
turn = 0; //可以优先让对方进入临界区
while (flag[0] && turn==0); //对方想进,且最后一次是自己“让梨”,那自己就循环等待
critical section;
flag[1] = false; //访问完临界区,表示自己已经不想访问临界区了
remainder section;
问题:不遵循“让权等待”原则,会发生忙等
3.进程互斥的硬件实现方法
- 中断屏蔽
利用“开/关中断指令”实现
···
关中断;
临界区;
开中断;
···
优点:简单高效
缺点:只适用于单处理机;只适用于操作系统内核进程
2. TestAndSet指令
TS指令,TestSandLock指令,TSL指令
old
记录是否已被上锁;再将lock
设为true
;
检查临界区是否已被上锁,若已上锁,则循环重复前几步
//lock 表示当前临界区是否被加锁,true表示已加锁,false表示未加锁
bool TestAndSet(bool *lock) {
bool old;
old = *lock; //old用来存放lock 原来的值
*lock = true; //无论之前是否已加锁,都将lock设为true
return old;
}
//使用 TSL 指令实现互斥的算法逻辑
while (TestAndSet (&lock)); //“上锁”并“检查”
临界区代码段...
lock = false; //“解锁”
剩余区代码段...
优点:实现简单,适用于多处理机环境
缺点不满足让权等待
3. Swap指令
Exchange 指令、XCHG 指令
//Swap 指令的作用是交换两个变量的值
Swap (bool *a, bool *b) {
bool temp;
temp = *a;
*a = *b;
*b = temp;
}
//使用 Swap 指令实现互斥的算法逻辑
//lock 表示当前临界区是否被加锁
bool old = true;
while (old == true) //临界区在之前为上锁状态
Swap (&lock, &old);
临界区代码段...
lock = false;
剩余区代码段...
逻辑、优缺点与TSL相同。
4. 信号量机制
信号量机制:用户进程通过操作系统提供的一对原语
来对信号量
进行操作。
信号量:表示系统中某种资源的数量。
原语:是由关中断/开中断指令实现。
一对原语:简称为P、V操作。
- 整型信号量:
- 概念:用一个整数型的变量作为信号量,数值表示某种资源的数量。
- 整型信号量与普通整型变量的区别:对信号量只能执行:初始化、P、V三种操作
- 整型信号量存在的问题:不满足让权等待原则
对整形信号量x,定义P操作及V操作原语如下:
P(x)
{
while(x<=0);
x=x-1;
}
V(x)
{
x = x+1;
}
- 记录型信号量:用记录型数据结构表示的信号量。
- S.value 表示某种资源数,S.L 指向等待该资源的队列
- P 操作中,一定是S.value–,之后可能需要执行 block 原语
- V 操作中,一定是S.value++,之后可能需要执行 wakeup 原语
- 注意:要能够自己推断在什么条件下需要执行 block 或 wakeup
- 可以用记录型信号量实现系统资源的“申请”和释放
- 可以用记录型信号量实现进程互斥、进程同步
5. 用信号量实现进程互斥、同步
- 信号量机制实现进程互斥
- 分析问题,划定临界区(如:对临界资源打印机的访问就应放在临界区)
- 设置互斥信号量 mutex,初值为
1
- 在
临界区之前
对信号量执行 P操作:P(mutex) - 在
临界区之后
对信号量执行 V操作:V(mutex)
- 信号量机制实现进程同步
- 分析问题,找出哪里需要实现“一前一后”的同步关系
- 设置同步信号量,初始值为
0
- 在
“前操作”之后
执行V
操作 - 在
“后操作”之前
执行P
操作
- 实现进程的前驱关系:
- 分析问题,画出前驱图,把每一对前驱关系都看成一个同步问题
- 为每一对前驱关系设置同步信号量,初值为0
- 在每个“前操作”之后执行
V
操作 - 在每个“后操作”之后执行
P
操作
- 注意:
- 互斥问题,信号量初值为1
- 同步问题,信号量初值为0
- 前驱关系问题,本质上就是更复杂的同步问题
- 除了互斥、同步问题外,还会考察有多少个资源的问题。有多少资源就把信号量初值设为多少。申请资源时进行P操作,释放资源时进行V操作。
6. 生产者-消费者问题
生产者进程每次生产一个产品放入缓冲区,消费者进程每次从缓冲区中取出一个产品并使用。
同步关系:缓冲区满时,生产者要等待消费者取走产品
同步关系:缓冲区空时(即没有产品时),消费者要等待生产者放入产品
互斥关系:缓冲区是临界资源,各进程必须互斥地访问。
信号量机制可实现互斥、同步、对一类系统资源的申请和释放。