根據註解表示:
在刪除節點時,如果要刪除的節點有右子節點,則刪除過程涉及將要刪除的節點替換為右子樹中遇到的第一個節點(249 ~ 254行)。在這個替換之後,會對新插入節點的右子節點進行更新操作(255行)。
同樣地,如果要刪除的節點沒有右子節點,替換過程涉及利用左子樹中找到的第一個節點。隨後,會對替換節點的左子節點進行更新操作。
在要刪除的節點既沒有左子節點也沒有右子節點的情況下,可以直接從樹中刪除該節點,並對被刪除節點的父節點進行更新操作(282行)。
特別跟 AVL tree 和 red-black tree 相比
實作:
設計效能評比程式,探討上述程式碼和 red-black tree 效能落差
第6行先判斷變數 alignment
是不是2的冪,判斷方式是透過將 alignment
與 mask = alignment - 1
做 bitwise and 運算,如果 alignment
是2的冪寫成二進制表達式時只會有一個 bit 是1 (假設第i個 bit 為1)剩餘的 bits 都是0,並且 mask
會變成0 ~ i-1 bits 都是1其餘的 bits 是0的狀況,所以兩者做 bitwise and 就會變成0如此就可以判斷是不是2的幂。
第7行透過剛剛計算出的 ~mask
代表0 ~ i-1 bits 都是0其餘的 bits 是1,所以當 sz + mask
與 ~mask
做 bitwise and 相當於把0 ~ i-1 bits 清成0,這就可以達到對齊的效果了。另外 sz + mask
的原因在於輸出要求大於等於 alignment
的記憶體對齊地址,如果要求變成小於等於的話則不需要另外加 mask
。
之所以要分 alignment
是不是2的冪是因為除法跟乘法需要的時間遠遠大於 bitwise 操作所需的時間,所以為了讓 align_up
更有效率才會分開來計算,並且在 kernel 中大部分 alignment 都是2的冪所以這個方法可以有效加速。
巨集:
__ALIGN_KERNEL_MASK(x, mask)
舉例說明:
在linux/mm/cma.c#L278中,kernel 需要計算出使用者要保留CMA的 base address 以及 size,並且這兩個值都必需是 alignment,就使用巨集ALIGN(x, a)來達成此目的。
在編譯參數中加入-fsanitize=thread
即可開啟 Thread Sanitizer,編譯後執行會出現以下警告:
從上圖 Write of size 那行可以看出 data race 出現在213行,並且從圖中 Previous read 那行指出345行正在讀取共同變數。這樣看來問題就很明顯了那主要是 pool 中用來表示 thread 狀態的 st
變數有 data race。
要解決這個問題只需要將213行跟214行對調即可,透過先 lock mtx_st
確保原本213行在改變狀態時345行無法去讀取(344行有lock)。