contributed by <doodoodog>
題目: 2023_sumer_quiz1
解釋上述程式碼運作原理,應該涵蓋測試方法、futex 使用方式、Linux 核心開發者針對 POSIX Threads 強化哪些相關 futex 實作機制等等
此程式碼的目的是在 Multi-Thread 的情況下能滿足所有 Task 能夠按順序完成。(範例 : 如果要執行 Task 3 就必須先執行 Task 2,如果要執行 Task 2 就必須先執行 Task 1 以此類推)。
在沒有 parent node 的情況下:
clock_wait()
中喚醒後因為沒有 parent node 存在。clock_tick()
透過cond_broadcast()
喚醒所有等待在 condvar 上的執行緒。node_signal()
來喚醒 node 0 獲取 mutex lock。在有 parent node 的情況下:
clock_wait()
中喚醒後因為存在 parent node 1。clock_tick()
透過cond_broadcast()
喚醒所有等待在 condvar 上的執行緒,並且進入到競爭 condvar 等狀態等待 node 0 完成。clock_wait()
中喚醒後會先做clock_tick()
透過cond_broadcast()
喚醒等待在 condvar 上的執行緒。node_signal()
來喚醒 node 0 獲得 mutex lock。node_wait()
並且透過node_signal()
來喚醒 node 1 獲得 mutex lockfutex 允許在最低程度的 Linux 核心參與,達到執行緒之間的同步。futex 的操作幾乎全部在使用者空間完成;只有當操作結果不一致從而需要仲裁時,才需要進入作業系統核心空間執行。這讓以 futex 為基礎的 lock 得高效進行:由於絕大多數的操作並不需要在多個行程之間進行仲裁,所以絕大多數操作都可以在應用程式空間執行,而不需要使用(相對高代價的)核心系統呼叫。
futex_wait
futex_wait
透過 System Call 在 User Spacee 來完成 sleep lock 的功能,sleep lock 與 busy lock 差異在於 sleep lock 在等待過程中不會占用 CPU 資源。
FUTEX_WAIT_PRIVATE
用 bit 來表示 futex 的屬性代表是 wait and non-share
mutex_trylock
透過 atomic_load_explicit
來檢查是否被上鎖,再用 atomic_fetch_or_explicit
嘗試上鎖。
mutex_lock
在 mutex_trylock
失敗後,這邊會短暫 Spin 來嘗試 mutex_trylock
目的是如果很快就可以拿到 lock 就不用進入 sleep(避免執行緒太頻繁進入到 sleep stage)。最後才會讓執行緒進入 sleep 等待 lock 資源。
futex_wake
futex_wake
透過 System Call 來喚醒因為沒有搶到 futex_wait 而進入睡眠的執行緒
mutex_unlock
執行緒在完成任務後需要釋放 lock,透過 futex_wake
系統呼叫來喚醒陷入沉睡在等待 lock 資源的執行緒 limit = 1
表示只有一個 lock 資源被釋放。
futex_requeue
futex_requeue
喚醒所有等待在 condvar 上的執行緒。limit
表示釋放的資源數量 INT_MAX
表示喚醒多少執行緒來競爭。
cond_broadcast
避免浪費喚醒操作所導致的執行緒切換,可以呼叫一次來減少競爭 mutex lock 的次數。
修改第 1 次作業的測驗 γ 提供的並行版本快速排序法實作,使其得以搭配上述 futex 程式碼運作
完整 程式碼。效能比較:
pthread | futex | |
---|---|---|
Run Time | 15.9s | 10.4 |
研讀〈並行程式設計: 建立相容於 POSIX Thread 的實作〉,在上述程式碼的基礎之上,實作 priority inheritance mutex 並確認與 glibc 實作行為相同,應有對應的 PI 測試程式碼
完整 程式碼。
實際優先權是 T1 > T2 > T3,執行順序 T3 → T2 → T1。以下做兩種實測,T3、T1 持有 Lock1,T2 持有 Lock2:
比照 skinny-mutex,設計 POSIX Threads 風格的 API,並利用內附的 perf.c (斟酌修改) 確認執行模式符合預期,過程中也該比較 glibc 的 POSIX Threads 效能表現