多處理器編程的藝術 第二章 互斥 (上)

2.1 時間

- 線程是個狀態(tài)機,其狀態(tài)的轉換稱為事件。

- 事件是瞬間發(fā)生的,我們假設不同的事件在不同的時間點發(fā)生。

- 事件間隔有重疊時,稱為 并發(fā)的。

2.2 臨界區(qū)

- 某個時刻僅能夠被一個線程執(zhí)行的代碼,稱為臨界區(qū)。

- 上面的特性,稱為 互斥。

-

+? 互斥:不同線程的臨界區(qū)之間沒有重疊。

+ 無死鎖:如果一個線程正在嘗試獲得一個鎖,那個總會成功的獲得這個鎖。

+ 無饑餓:每個試圖獲得鎖的線程最終都能成功。//無饑餓意味著無死鎖。

//無饑餓特性不保證線程在進入臨界區(qū)以前需要等待多長時間。

- 即使程序所使用的每個鎖都滿足無死鎖特性,該程序也可能死鎖。

2.3 雙線程解決方案

2.3.1 LockOne算法

LockOne算法的缺陷:**LockOne算法在交叉執(zhí)行的時候會出現(xiàn)死鎖。若事件writeA(flag[A] = true)與writeB(flag[B] = true)在事件readA(flag[B]==flase)和readB(flag[A]==false)之前發(fā)生,那么兩個線程都將陷入無窮等待。

2.3.2 LockTwo算法

LockTwo類存在的缺陷:當一個線程完全先于另一個線程執(zhí)行的時候就會出現(xiàn)死鎖。但是兩個線程并發(fā)地執(zhí)行,卻是成功的。由此,我們看到LockOne與LockTwo算法彼此互補,于是將兩者結合的算法Peterson算法實現(xiàn)了。

2.3.3 Peterson鎖

Peterson鎖算法://雙線程互斥算法

class Peterson implements Lock {

// thread-local index, 0 or 1

private volatile boolean[] flag = new boolean[2];

private volatile int victim;

public void lock() {

int me = ThreadID.get();

int he = 1 - me;

flag[me] = true;??????????? // I’m interested

victim = me;??????????????? // you go first

while (flag[he] && victim == me) {}; // wait

}

public void unlock() {

int me = ThreadID.get();

flag[me] = false;?????????? // I’m not interested

}

}

-? Peterson鎖是滿足互斥特性,是無饑餓,無死鎖的。

2.4 過濾鎖(分層策略)

算法代碼:

class Filter implements Lock {

int[] level;

int[] victim;

public Filter(int n) {

level = new int[n];

victim = new int[n]; // use 1..n-1

for (int i = 0; i < n; i++) {

level[i] = 0; //[1]

}

}

public void lock() {

int me = ThreadID.get();

for (int i = 1; i < n; i++) { //attempt level 1 //[2]

level[me] = i;

victim[i] = me;

// spin while conflicts exist

while ((?k != me) (level[k] >= i && victim[i] == me)) {}; //[3]

}

}

public void unlock() {

int me = ThreadID.get();

level[me] = 0;

}

}

說明:? - n 元整數(shù)組level [], level[A]的值表示線程A正在嘗試進入的層。

- 每個層都有一個victim[l] 域, 用來選出線程,“留守”本層。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內(nèi)容