st_rotate_left
: 旋轉左子樹變平衡st_rotate_right
: 旋轉右子樹變平衡st_balance
: 左子樹高度-右子樹高度st_max_hint
: 樹的高度st_update
: st_balance
< -1,代表右子樹太重,所以要st_rotate_right
,反之,要st_rotate_left
。在st_update
的最後會檢查hint是否改變,若是改變,親代的hint就可能改變,因此要向上更新。另外,由於rotate的操作只有在update中會發生,所以也只有在st_update
中需要更新hintst_insert
: 需要提供root
, parent
, node
和dir
。root
是整棵樹的根,parent
代表node
的親代,dir
則代表node
是在parent
的左邊還是右邊。實作方法直觀,將node
附值給parent
的dir
,將parent
設為node
的親代,st_update
樹的parent
這個節點,因為可能需要rotate,這會更新整棵樹。st_replace_[left/right]
: 用l/r
節點覆寫n
節點st_remove
: 刪除節點del
。如果有右子樹會先用右子樹的最小值複寫del
,若沒有右子樹則會用左子樹的最大值覆寫del
。若沒有子樹則直接刪除即可。當我們把least/most節點移動到del
時,我們需要更新他原本的親代的hint
,同時,如果因為移動導致不平衡,需要旋轉成平衡子樹。container_of
: 透過offsetof
取得類別成員在記憶體中,在pack中的相對位置,再用該成員的記憶體位置減去該相對位置,從而得到該類的記憶體位置在st_remove
中會先檢查是否有右子樹,若沒有右子樹則會檢查左子樹。由於這是一個平衡樹,且左右子樹高度差不大於1,所以在沒有右子樹的時候,即便有左子樹也只會有一個節點。所以我們不需要再去找左子樹中的最大值,可以省略st_last
。並且,由於st_replace_left
之後,del
不會再有子代,所以直接更新del
即可。
根據doc/Documentation/rbtree.txt比較rbtree
與S-Tree
的效能。使用Uftrace比較兩者在Insert以及Remove時,所使用的旋轉次數以及耗費時間。
觀察alignment = 4 = 0100的情況
可以發現align_up
做的事情就是在第一、二個位元有1的時候,將其清空,並且加上alignment
。再觀察alignment = 8 = 1000的情況
跟alignment = 4時的狀況相似,只是多了第三的位元。所以我們根據觀察寫出第一個版本的align_up
。
但是我們希望不要使用if
來完成align_up
。再觀察一次align_up
的步驟
再觀察align_up
之後會是一樣的數,可以發現在需要進行上述步驟的數值都是即便-1之後再做一樣的步驟還是會有一樣的結果。同時,已經對其的數值(116)在-1之後,如果做同樣的步驟,也會得到相同的結果
所以先將sz
-1,就不需要判斷是否需要對齊
由於經過(sz - 1) & ~mask
之後,+ mask
等價於| mask
,所以我們可以改寫成這樣
最後,可以發現先& ~mask
再| mask
等價於| mask
,因此答案應該是這樣
觀察後發現HHHH
是發生在狀態改變為ts_idle
的時候,只有在做完qsort-algo
之後才會改變為ts_idle
的狀態。所以再來要做的事情應該是等待ts_term
。查找當狀態改變為ts_term
時的行為,可以看到在f3
以及JJJJ
之前都會改變狀態為ts_term
,由於JJJJ
是我們要寫的作業,因此推測這裡的行為跟f3
是一樣的,都需要發送訊號給qs->cond_st
。
透過ThreadSanitizer檢查data race的問題
clang
編譯qsort-mt.c
qsort
得到ThreadSanitizer的報告,發現有一個data race的問題