動機
只是記錄用,因為在現代計算機架構下,基本上都沒用 但有面試問過,所以寫一下
Peterson algorithm
用flag與term來阻止對方
def f1():
flag[0] = true
turn = 1
while flag[1] == true and turn == 1:
# busy wait
# critical section
# ...
# end of critical section
flag[0] = false
def f1():
flag[1] = true
turn = 0
while flag[0] == true and turn == 0:
# busy wait
# critical section
# ...
# end of critical section
flag[1] = false
為什麼需要turn? 不然flag都會是true
Lamport’s bakery algorithm
利用sequence嚴格遞增,對thread做sort
// Entering: array [1..NUM_THREADS] of bool = {false};
// Number: array [1..NUM_THREADS] of integer = {0};
lock(integer i) {
Entering[i] = true;
Number[i] = 1 + max(Number[1], ..., Number[NUM_THREADS]);
Entering[i] = false;
for (integer j = 1; j <= NUM_THREADS; j++) {
// Wait until thread j receives its number:
while (Entering[j]) { /* nothing */ }
// Wait until all threads with smaller numbers or with the same
// number, but with higher priority, finish their work:
while ((Number[j] != 0) && ((Number[j], j) < (Number[i], i))) { /* nothing */ } // 有沒有想到raft的投票,或是at-least-updated
}
}
unlock(integer i) {
Number[i] = 0;
}
問題是?
現代cpu會reorder程式碼
像peterson的可以reorder成
turn = 1
flag[0] = true
# ...
turn = 0
flag[1] = true
bakery可以reorder成
lock(integer i) {
Entering[i] = true;
Entering[i] = false; // 之後變成只剩false
Number[i] = 1 + max(Number[1], ..., Number[NUM_THREADS]);
// ...
}
因為想做atomic的資料與做atomic的資料沒有關聯(因果關係)
感覺比較可以的: Szymański’s algorithm
把狀態切的細一點,分成 0: 在外面,未申請訪問臨界區 1: 在入口門外等待 2: 在入口門內等待其它提出申請的進程都進入入口門 3: 正在進入入口門 4: 入口門關閉,在等候室里等待進入臨界區,或正在訪問臨界區
// Entry protocol
flag[self] = 1 // Standing outside waiting room
await(all flag[1..N] ∈ {0, 1, 2}) // Wait for open door
flag[self] = 3 // Standing in doorway
if any flag[1..N] = 1: // Another process is waiting to enter
flag[self] = 2 // Waiting for other processes to enter
await(any flag[1..N] = 4) // Wait for a process to enter and close the door
flag[self] = 4 // The door is closed
await(all flag[1..self-1] ∈ {0, 1}) // Wait for everyone of lower ID to finish exit protocol
// Critical section
// ...
// Exit protocol
await(all flag[self+1..N] ∈ {0, 1, 4}) // Ensure everyone in the waiting room has
// realized that the door is supposed to be closed
flag[self] = 0 // Leave. Reopen door if nobody is still in the waiting room