实现进程互斥的硬件方法
中断禁用
单处理器系统中进程在进入临界区前禁用中断,离开临界区后启用中断,这样保证进程在临界区时不会被打断,不会被抢占
while (true){
//禁用中断
//临界区
//启用中断
//其他部分
}
缺点:
影响效率,所有其他进程都等待在临界区的进程,可能让其他进程处于饥饿状态
不能用于多处理器机器上
TestSet指令
原子操作机器指令,对传进来的值更新为1,并返回旧的值。
C语言版本的伪代码,只用来解释TestSet指令的逻辑,真实实现是原子机器指令
#define LOCKED 1
int TestAndSet(int* lockPtr) {
int oldValue;
// -- Start of atomic segment --
// This should be interpreted as pseudocode for illustrative purposes only.
// Traditional compilation of this code will not guarantee atomicity, the
// use of shared memory (i.e., non-cached values), protection from compiler
// optimizations, or other required properties.
oldValue = *lockPtr;
*lockPtr = LOCKED;
// -- End of atomic segment --
return oldValue;
}
我们可以给予TestSet指令来实现对临界区加锁解锁的操作
volatile int lock = 0;
void Critical() {
while (TestAndSet(&lock) == 1); // add lock
critical section // only one process can be in this section at a time
lock = 0 // release lock when finished with the critical section
}
在上述代码中,lock有0跟1两个值,初始化为0,那么第一个执行到while (TestAndSet(&lock) == 1);的进程A会跳过while循环,因为TestAndSet返回lock的旧值0,然后lock就成了1,进程A进入临界区,此时如果进程B也执行到while循环,TestAndSet会一直返回1,一直循环下去。此时如果进程A已经离开临界区,把lock设为了0,那么在等待的进程B会跳出while循环,进入临界区,这就实现了对临界区的加锁解锁操作,保证了同一时间只有一个进程会进入临界区。
上述过程对多个进程也同样适用,只有lock=0时第一个执行到while循环的进程能进入临界区,其他进程的lock一直会是1,知道lock被重新设置为0.
这都要归功于TestAndSet的原子操作,如果其不是原子操作,可能会两个进程在*lockPtr=0时都执行了oldValue = *lockPtr; 然后再执行*lockPtr = LOCKED;此时两个进程都会返回0,导致两个进程同时进入临界区
优点:适用于单处理器或共享内存的多处理器上的任意数量的进程
简单且易证明
支持多个临界区,每个临界区有自己的变量
缺点:
while循环等待时一直消耗CPU时间,存在忙等待(busy-waiting)问题
可能饥饿,一个进程离开临界区而多个进程在等待进入临界区时,选择哪个进程进入是随机的,因为有的进程可能会一直无法进入临界区
可能死锁,进程P1进入临界区,然后P1被中断并把CPU让给等级更高的P2进程,P2进程会一直忙等待,无法进入临界区,而此时P1不会从其他状态转换为运行态,因为P1等级比P2低,P1在等待P2离开运行态,而P2一直在等P1离开临界区,形成死锁
https://www.bilibili.com/video/av6538245?p=62
https://en.wikipedia.org/wiki/Test-and-set
Exchange指令
原子操作机器指令,伪代码如下
void exchange(int * register,int *memory){
int temp;
temp=*memory;
*memory=*register;
*register=temp;
}
用exchange指令实现互斥
int bolt;
void Process(int i){
while (true){
int keyi=1;
do exchange(keyi,bolt)
while (keyi!=0);
//临界区代码
bolt=0
//其他部分
}
}
假设一共有N个进程,i对应的是0,1,。。。N-1,那么可以保证任意时刻bolt+key0+key1+…+keyN-1==N恒为True,如果bolt=0,则无进程进入临界区,其他时候任意一个进程的keyi=0,bolt=1,表示i进程进入临界区,其他进程在等待
优点: 如TestSet指令
缺点: 如TestSet指令