目录
1--原子操作
原子操作(Atomic Operation)是指一次不存在任何中断或者失败的互斥;其一般具有以下状态:① 该操作成功结束; ② 该操作根本未被执行,且未发现任何部分执行的状态;
2--临界区
临界区(Critical section)是指进程中的一段代码区域,其对应于进程需要访问共享资源,而另一个进程也处于相应的代码区域时,这段代码区域不会被另一个进程执行;
3--互斥
互斥(Mutual exclusion)是指当一个进程处于临界区并访问共享资源时,没有其他进程会处于临界区并且访问任何相同的共享资源;
4--死锁
锁(lock)是指对数据加上保护装置,使其无法被访问;
解锁(unlock)是指解除对数据的保护,使其可以被访问;
死锁(Dead lock)是指两个或以上的进程,在相互等待完成特定任务时,由于相互等待而导致各自的任务无法顺利执行;
5--饥饿
饥饿(Starvation)是指一个可执行的进程,被调度器持续忽略,导致其虽处于可执行状态但一直未被执行;
6--临界区设置
临界区基本属性:
① 实现互斥性:同一时间临界区中最多存在一个线程;
② Progress:一个线程想要进入临界区,其一定会成功;(即肯定能进入临界区,只是有先后顺序)
③ 有限等待:一个线程处于临界区入口时,在该线程的请求被接受之前,其他线程进入临界区的时间有限制;(即其他线程不会无限等待,在有限时间后其他线程会顺利进入临界区)
④ 无忙等待(可选):如果一个进程在等待进入临界区,其在进入前可以被挂起;
实现临界区代码保护的三种方法:
① 禁用硬件中断;
② 基于软件的解决方法;
③ 高级抽象方法;
6-1--禁用硬件中断
基本概念:
进入临界区,则禁用中断;离开临界区,则开启中断;
由于禁止了中断,就不会产生上下文的进程切换,因此也没有并发;
缺陷:
中断被禁用,线程就无法被停止,同时整个系统的线程都会停下,其他线程可能会处于饥饿状态;
禁用硬件中断仅限于单核CPU;
6-2--基于软件的解决方法
基本概念:
通过 Peterson、dekker 和 Bakery 等算法实现线程间的互斥;
缺陷:
产生忙等待,同时浪费CPU资源;
需要线程间实现数据共享;
6-3--高级抽象方法
基本概念:
利用原子操作实现锁,例如 Test-and-Set 和 Exchange 两个原子操作(代码不会被打断,只能一次成功执行)构建锁;
Test-and-Set 测试与置位:
从内存中读取值,判断该值是否为1,并返回 True 或 False,最后将内存值设置为1;
Exchange 交换:
交换内存中的两个值;
利用 Test-and-Set 和 Exchange 两个原子操作,可以实现锁:
class Lock{
int value = 0;
}
// 如果锁被释放,则test-and-set读取0并将值设置为1,即锁被设置为忙并且需要等待完成
// 如果锁处于忙状态,则test-and-set读取1并将值设置为1,即不改变所得状态,自身不断循环(spin)
Lock::Acquire(){
while(test-and-set(value)); // spin
}
Lock::Release(){
value = 0; // 释放锁
}
int key;
do{
key = 1;
while(key == 1) exchange(lock, key); // 锁
critical section; // 临界区
lock = 0; // 退出临界区,解锁
remainder section;
}
锁实现互斥的缺陷:
可能会导致忙等待,消耗处理器的时间;
当进程离开临界区并且多个进程在等待时,会导致进程饥饿;