# Critical Section Problem ## Race condition * 多個行程同時對同一個資料存取 * 存取的順序影響結果 * 解決辦法 : 一次僅允許一個行程存取 ## Critical Section * 一個<font color='Orange'>程式碼片段</font>,用來放置共享變數 ![](https://i.imgur.com/IppV0Lb.png) ## Critical Section Problem * 必須滿足下列三個要求 1. __Mutual exclusion__ - 任意時間點,只允許一個行程進入 2. __Progress__ - 不想進去的人不能妨礙別人 - 決定誰可以進去的時間是有限的 3. __Bounded waiting__ - 從請求進入到獲准的時間是有限的 * n 個行程<font color="Orange">最多等 n-1 次</font> ## Peterson's Solution * A software-based solution * Two process solution ``` C int turn; Boolean flag[2]; ``` * `turn` : 現在輪到誰進去 * `flag[i] = true` : P~i~ 準備好了 :sunglasses: * Peterson's solution for process P~i~ ``` C do { flag[i] = TRUE; turn = j; while(flag[j] && turn == j); CRITICAL SECTION flag[i] = FALSE; REMAINDER SECTION } ``` 1. 滿足Mutual exclusion - 如果`flag[j] == false`或`turn = i`, P~i~ 可以進去 - 如果都想進去, `flag[i] == flag[j] == true` - 然而`turn` <font color="Orange">只能是其中一個</font> - 只有 P~i~ 或 P~j~ 其中一個能先進去 - 另一個要等他結束 2. 滿足Progess 1. P~i~ 準備好了 - 如果 P~j~ 還沒準備好(在remainder section) - 那麼`flag[j] == false` - P~i~ 可以進去 2. P~i~ 和 P~j~ 都準備好了 - `flag[i] == flag[j] == true` - `turn == i` P~i~ 進去 - `turn == j` P~j~ 進去 3. 滿足Bounded waiting - 當 P~i~ 離開後又想再進去一次 - 此時 P~i~ 會執行 `turn = j` - P~i~ 就進不去了 - 因此 P~j~ 最多等待一次 ## Synchronization Hardware ### Atomic operation * 不會被中斷或是context switch * 一旦開始執行就會執行到結束 ### Test and Set ``` C boolean test_and_set(boolean *target) { boolean *rv = target; *target = true; return rv; } ``` ``` C // initialize varible lock to false do { while(test_and_set(&lock)); // critical section lock = false; // remainder section } while(true); ``` * 回傳舊值,並將舊值改為true * 只有第一次會是false * 第一個執行 `test_and_set` 的 process 會將 lock 值設為 true 並回傳 false * 其他想要拿 lock 的 process 會卡在 while 迴圈 ### Compare and Swap ``` C int compare_and_swap(int *value, int expected, int new_value) { int temp = *value; if(*value == expected) *value = new_value; return temp; } ``` ``` C // initialize varible lock to false do { while(compare_and_swap(&lock, 0, 1) != 0); // critical section lock = 0; // remainder section } while(true); ``` * 回傳舊值,並比較lock的值 * 如果是 false(0) 把 lock 值改為 true(1) * 如果是 true(1) 就還是 true(1) * 概念與 `test_and_set` 同 ### 小結 * 這兩個演算法都<font color="Orange">不滿足bounded-waiting</font> * 一個用 `test_and_set()` 改良的演算法可以滿足所有 critical-section 的條件 ### 修正後的 `test_and_set()` ``` C // initialize varible lock to false do { waiting[i] = true; key = true; while(waiting[i] && key) key = test_and_set(&lock); waiting[i] = false; // critical section j = (i+1) % n; while((j != i) && !waiting[j]) j = (j+1) % n; if(j == i) lock = false; else waiting[j] = false; //remainder section } while(true) ``` * `waiting[i] = ture` means P~i~ is waiting * 只有 `waiting[i] == false` 或 `key == false` 才能進入 critical path * 第一個執行 `test_and_wait()` 的 process 會讓 `lock = true` , 其他人就要等 * 如果沒有 process 在等,釋放 lock * 如果有,讓 P~j~ 拿著lock,進入 critical section <div style="border-top:1px dashed #cccccc;height: 1px;overflow:hidden"></div> 1. 滿足 Mutual exclusion * 一個行程離開,一個行程獲得機會進去 * `waiting[j] = false` 2. 滿足 Progress * 一個行程離開 critical section 後,會把 lock 設成 false 或把 waiting[j] 設成 false * 這些都會決定要讓哪個在等的行程進入 critical section 3. 滿足 Bounded-waiting * 當一個行程離開後,會scan waiting array (i, i+1, ... n, 1, 2, ... i-1) * 任一行程最多等n-1次 --- #### last edit > [name=dot] [time=Sun, Dec 22, 2019, 8:58 PM] [HOME PAGE](/@dot/B1LEoYNRS) :stuck_out_tongue: {%hackmd theme-dark %} ###### tags : `OS` `CSIE`