硬件同步
test_and_set()
boolean test_and_set(boolean *target){
boolean rv = *target;
*target = true;
return rv;
}
先声明一个布尔变量lock,初始化为false。
当没有进程在临界区内时,lock为false, 当有进程在临界区内时,lock为true。
当一个进程想要进入临界区时,它会先调用test_and_set(),test_and_set()返回lock的原始值,并将lock赋值为true。
若返回值为false,则该进程可进入临界区
若返回值为true,则表示有进程在临界区,所以该进程需循环调用test_and_set(),直到没有进程在临界区内。
采用指令test_and_set的进程实现:
do{
while(test_and_set(&lock));
lock = false;
}while(true);
compare_and_swap()
int compare_and_swap(int *value, int expected, int new_value){
int temp = *value;
if(*value == expected)
*value = new_value;
return temp;
}
指令compare_and_swap()需要三个操作数。
首先声明一个全局布尔变量lock,初始化为0。
当临界区内有进程时,lock值为1,临界区内没有进程时,lock值为0
当一个进程需要进入临界区时,首先调用compare_and_swap(&lock, 0, 1),中间为期望值,最后面为新增值,返回lock原始值。
如果没有进程在临界区,lock值为0,调用之后,因为lock值等于期待值0,lock值变为1,并且返回0,于是进入临界区。
如果有进程在临界区,lock值为1,调用之后,lock值不等于期待值,返回值为1不等于0,于是循环调用等待。
采用指令compar_and_swap()的指令实现:
do{
while(compare_and_swap(&lock, 0, 1) != 0);
lock = 0;
}while(true);
满足有限等待
上述并不满足有限等待条件,下面实现满足有限等待的test_and_set()
进程共用的数据结构为:
boolean waiting[n]
boolean lock
这些结构初始化为false。
只有waiting[i] == false 或者 key == false时,进程pi才能进入临界区
do{
waiting[i] = true;
key = true;
while(waiting[i] && key)
key = test_and_set(&lock);
waiting[i] = false;
//当队列中下一个进程wainting为true,时,表示要进入临界区,于是得到j
j = (i+1) % n;
while((j!= i) && !waiting[j])
j = (j+1)%n;
//把lock设为false或者把waiting[j]设为false,都能使j进程推出循环等待,进入临界区。
if(j == i)
lock = false;
else
waiting[j] = false;
}while(true);
当wainting[i] == true时,代表该进程想进入临界区。
key初始化为true,当临界区没有进程时,lock为false,调用test_and_set,key设为false,lock设为true,该进程进入临界区。
当临界区有进程时,lock为true,key一直为true,于是循环调用等待,直到进程离开临界区。
当该进程离开临界区时,wainting[i]设为false,表示不想进入临界区。
#互斥锁
每个互斥锁有一个布尔变量available,它的值表示锁是否可用。
如果琐是可用的,那么调用acquire()会成功,并且锁不再可用
当一个进程试图获取不可用的锁时,它会阻塞,知道锁被释放。
acquire(){
while (!available);
availablle = false;
}
release(){
available = true;
}
互斥锁的缺点是需要忙等待。
当有一个进程在临界区中,任何其他进程在进入临界区时必须连续循环地调用acquire()。
** 考虑如何使用原子硬件指令实现互斥锁。假设互斥锁的结构如下:
typedef struct{
int available;
}lock;
当available为0时,表示锁可用;当available为1时,表示锁不可用。通过这个struct,说明如何采用指令test_and_set()和compare_and_swap()来实现如下函数,一定包括任何可能必要的初始化:
- void acquire(lock *mutex)
void acquire(lock *mutex){
while(test_and_set(*mutex.available));
}
void acquire(lock *mutex){
while(compare_and_swap(*mutex.available, 0, 1) != 0);
}
- void release(lock *mutex)
void release(lock *mutex){
*mutex.available = 0;
}