硬件同步
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;
}