# 2021q3 Homework2 (hp) contributed by < `GundamBox` > ###### tags: `linux2021` ## 開發環境 - CPU - Intel i3-4160 (2C4T) - Distro - Ubuntu 20.04-LTS - Kernel - 5.8.0-63-generic ## 開發之前 - [作業連結][linux2021-summer-homework2] ## 題目 ### 1. 解釋上述程式碼運作原理 #### main - `pthread_create` 建立 `thread` 並依照奇偶數分配動作 `list_insert` 與 `list_delete` #### list_insert ```mermaid stateDiagram-v2 [*] --> 檢查`key`是否在`list`中 state if_exist <<choice>> 檢查`key`是否在`list`中 --> if_exist if_exist --> 將找到的`node`釋放,並將該`thread`的`hazard_pointers`狀態清除: 有 if_exist --> 建立新的`node`並加到`list`的尾端 : 沒有 將找到的`node`釋放,並將該`thread`的`hazard_pointers`狀態清除 --> 失敗 建立新的`node`並加到`list`的尾端 --> `atomic`操作是否完成 state if_atomic <<choice>> `atomic`操作是否完成 --> if_atomic if_atomic --> 清除該`thread`的`hazard_pointer`的狀態: 完成 if_atomic --> 檢查`key`是否在`list`中: 未完成 清除該`thread`的`hazard_pointer`的狀態 --> 成功 ``` #### list_delete ```mermaid stateDiagram-v2 [*] --> 檢查`key`是否在`list`中 state if_exist <<choice>> 檢查`key`是否在`list`中 --> if_exist if_exist --> 檢查找到的`node`下一個節點是否被改變: 有 if_exist --> 將找到的`node`釋放,並將該`thread`的`hazard_pointers`狀態清除 : 沒有 將找到的`node`釋放,並將該`thread`的`hazard_pointers`狀態清除 --> 失敗 state if_next_changed <<choice>> 檢查找到的`node`下一個節點是否被改變 --> if_next_changed if_next_changed --> 檢查`key`是否在`list`中: 被改變 if_next_changed --> 檢查`curr`是否被改變: 未改變 state if_curr_changed <<choice>> 檢查`curr`是否被改變 --> if_curr_changed if_curr_changed --> 將該`thread`的`hazard_pointers`狀態清除: 被改變 if_curr_changed --> 將該`thread`的`hazard_pointers`狀態清除並執行GC: 未改變 將該`thread`的`hazard_pointers`狀態清除 --> 成功 將該`thread`的`hazard_pointers`狀態清除並執行GC --> 成功 ``` #### 細節 - 避免 `cacheline` 影響結果 - `aligned_alloc` - `CLPAD` - `alignas(128)` - `list_hp` 的 `hp` - 長度為 `HP_MAX_THREADS` 的指標陣列 - 等於每個 `thread` 都 - 在執行 `list_hp_new` 的時候,每個陣列元素都會分配到長度為 `CLPAD * 2` 個的空間 #### 執行結果解釋 ```bash $ gcc -Wall -o list list.c -lpthread -g -fsanitize=thread $ ./list inserts = 4098, deletes = 4098 ``` - insert - `list_new` 的 `head` 跟 `tail` 會各做一次 insert - `N_THREADS` 有一半做 `insert_thread`,共 `N_ELEMENTS` * (`N_THREADS` / 2) 次的 insert - 加總起來為 2 + 128 * 32 = 2 + 4096 = 4098 - delete - `head` 跟 `tail` 會各做一次 delete - `N_THREADS` 有一半做 `delete_thread`,共 `N_ELEMENTS` * (`N_THREADS` / 2) 次的 delete - 加總起來為 2 + 128 * 32 = 2 + 4096 = 4098 ### 2. 指出改進空間並著手實作 剛開始沒頭緒,參考同學`< R0inHizakura >`的[作業][RinHizakura_2021q3_homework2_hp]後找到靈感 1. 確認 `list` 的操作是對的 2. 確認 `hazard pointer` 的操作是對的 #### 改進過程 ##### 驗證原本的程式碼在單一執行緒執行結果 - 先將 `N_ELEMENTS` 改為 5 觀察單一執行緒的結果 - 加入 `debug_list_print()` ```c void debug_list_print(list_t *list) { list_node_t *curr = NULL, *next = NULL; printf("debug info: "); curr = get_unmarked_node(list->head); for (; curr; curr = get_unmarked_node(curr->next)) { #if DEBUG_PRINT if (get_unmarked_node(curr->next)) { printf("0x%012lx -> ", curr->key); } else { printf("0x%012lx", curr->key); } #endif next = get_unmarked_node(curr->next); if (next) { assert(curr->key < next->key); } } #if DEBUG_PRINT printf("\n"); #endif } ``` - 確認 linked list 的操作在單一執行緒的情況下是否正確 ```c int main(void) { list_t *list = list_new(); insert_thread(list); debug_list_print(list); list_destroy(list); fprintf(stderr, "inserts = %zu, deletes = %zu\n", atomic_load(&inserts), atomic_load(&deletes)); return 0; } ``` - 執行結果 ```bash list: list.c:389: main: Assertion `curr->key < next->key' failed. [1] 189660 abort (core dumped) ./list ``` - 啟動 `DEBUG_PRINT` ```bash debug info: 0x564383ebf060 -> 0x564383ebf068 -> 0x564383ebf070 -> ..... 0x564383ebf458 -> 0x000000000000 -> 0xffffffffffffffff ``` ##### 改進 `list` 操作 根據 [A Pragmatic Implementation of Non-Blocking Linked Lists][A_Pragmatic_Implementation_of_Non-Blocking_Linked_Lists] 這篇論文改進 `list` 的操作 - insert 1. find 0x02 2. 進入 `while` 迴圈前 ```graphviz digraph first_insert { node [shape = box] rankdir = LR head [label = "{head | 0x00 |<n> next}", shape = record]; tail [label = "{tail | 0xff |<n> next}", shape = record]; prev [label = "prev", shape = plaintext] curr [label = "curr", shape = plaintext] next [label = "next", shape = plaintext] null [label = "NULL", shape = plaintext] head -> tail tail -> null prev -> head curr -> head next -> null } ``` 3. 進入 `while` 迴圈 ```graphviz digraph first_insert { node [shape = box] rankdir = LR head [label = "{head | 0x00 |<n> next}", shape = record]; tail [label = "{tail | 0xff |<n> next}", shape = record]; prev [label = "prev", shape = plaintext] curr [label = "curr", shape = plaintext] next [label = "next", shape = plaintext] null [label = "NULL", shape = plaintext] head -> tail tail -> null prev -> head curr -> head next -> tail } ``` 4. `next == tail` 成立 ```graphviz digraph first_insert { node [shape = box] rankdir = LR head [label = "{head | 0x00 |<n> next}", shape = record]; tail [label = "{tail | 0xff |<n> next}", shape = record]; prev [label = "prev", shape = plaintext] curr [label = "curr", shape = plaintext] next [label = "next", shape = plaintext] null [label = "NULL", shape = plaintext] head -> tail tail -> null prev -> head curr -> head next -> tail } ``` 5. insert-1 - 原本的 `insert` 會讓 `node->next` 指向 `head`,造成前面錯誤的結果 ```graphviz digraph first_insert { node [shape = box] rankdir = LR head [label = "{head | 0x00 |<n> next}", shape = record] tail [label = "{tail | 0xff |<n> next}", shape = record] new_node [label = "{node | 0x02 |<n> next}", shape = record] head -> tail new_node -> head tail -> null null [label = "NULL", shape = plaintext] } ``` - 應該改為 `atomic_store_explicit(&node->next, (uintptr_t) next, memory_order_relaxed);` ```graphviz digraph first_insert { node [shape = box] rankdir = LR head [label = "{head | 0x00 |<n> next}", shape = record] tail [label = "{tail | 0xff |<n> next}", shape = record] new_node [label = "{node | 0x02 |<n> next}", shape = record] head -> tail new_node -> tail tail -> null prev -> head curr -> head next -> tail prev [label = "prev", shape = plaintext] curr [label = "curr", shape = plaintext] next [label = "next", shape = plaintext] null [label = "NULL", shape = plaintext] } ``` 6. insert-2 - `atomic_compare_exchange_strong(prev, &tmp, (uintptr_t) node)` 會把 head 替換掉,應該讓 `prev->next` 或 `curr->next` 也就是 `head->next` 指向 `node` ```graphviz digraph first_insert { node [shape = box] rankdir = LR tail [label = "{tail | 0xff |<n> next}", shape = record] new_node [label = "{node | 0x02 |<n> next}", shape = record] new_node -> tail tail -> null null [label = "NULL", shape = plaintext] } ``` - 改進為 ```c uintptr_t tmp = get_unmarked(curr->next); if (atomic_compare_exchange_strong(&curr->next, &tmp, (uintptr_t) node)) { ... } ``` ```graphviz digraph first_insert { node [shape = box] rankdir = LR head [label = "{head | 0x00 |<n> next}", shape = record] tail [label = "{tail | 0xff |<n> next}", shape = record] new_node [label = "{node | 0x02 |<n> next}", shape = record] head -> new_node new_node -> tail tail -> null prev -> head curr -> head next -> tail prev [label = "prev", shape = plaintext] curr [label = "curr", shape = plaintext] next [label = "next", shape = plaintext] null [label = "NULL", shape = plaintext] } ``` 7. 結果 ```bash debug info: 0x000000000000 -> 0x55b773f22060 -> 0x55b773f22068 -> ..... 0x55b773f22080 -> 0xffffffffffffffff ``` - delete 1. find 0x02 2. 進入 `while` 迴圈前 ```graphviz digraph first_insert { node [shape = box] rankdir = LR head [label = "{head | 0x00 |<n> next}", shape = record] n1 [label = "{n1 | 0x02 |<n> next}", shape = record] n2 [label = "{n2 | 0x04 |<n> next}", shape = record] n3 [label = "{n3 | 0x06 |<n> next}", shape = record] tail [label = "{tail | 0xff |<n> next}", shape = record] prev [label = "prev", shape = plaintext] curr [label = "curr", shape = plaintext] next [label = "next", shape = plaintext] null [label = "NULL", shape = plaintext] head -> n1 n1 -> n2 n2 -> n3 n3 -> tail tail -> null prev -> head curr -> head next -> null } ``` 3. 進入 `while` 迴圈 ```graphviz digraph first_insert { node [shape = box] rankdir = LR head [label = "{head | 0x00 |<n> next}", shape = record] n1 [label = "{n1 | 0x02 |<n> next}", shape = record] n2 [label = "{n2 | 0x04 |<n> next}", shape = record] n3 [label = "{n3 | 0x06 |<n> next}", shape = record] tail [label = "{tail | 0xff |<n> next}", shape = record] prev [label = "prev", shape = plaintext] curr [label = "curr", shape = plaintext] next [label = "next", shape = plaintext] null [label = "NULL", shape = plaintext] head -> n1 n1 -> n2 n2 -> n3 n3 -> tail tail -> null prev -> head curr -> head next -> n1 } ``` 4. `!(0x00 < 0x02)` 為 false ```graphviz digraph first_insert { node [shape = box] rankdir = LR head [label = "{head | 0x00 |<n> next}", shape = record] n1 [label = "{n1 | 0x02 |<n> next}", shape = record] n2 [label = "{n2 | 0x04 |<n> next}", shape = record] n3 [label = "{n3 | 0x06 |<n> next}", shape = record] tail [label = "{tail | 0xff |<n> next}", shape = record] prev [label = "prev", shape = plaintext] curr [label = "curr", shape = plaintext] next [label = "next", shape = plaintext] null [label = "NULL", shape = plaintext] head -> n1 n1 -> n2 n2 -> n3 n3 -> tail tail -> null prev -> n1 curr -> n1 next -> n1 } ``` 5. 下一次迴圈 ```graphviz digraph first_insert { node [shape = box] rankdir = LR head [label = "{head | 0x00 |<n> next}", shape = record] n1 [label = "{n1 | 0x02 |<n> next}", shape = record] n2 [label = "{n2 | 0x04 |<n> next}", shape = record] n3 [label = "{n3 | 0x06 |<n> next}", shape = record] tail [label = "{tail | 0xff |<n> next}", shape = record] prev [label = "prev", shape = plaintext] curr [label = "curr", shape = plaintext] next [label = "next", shape = plaintext] null [label = "NULL", shape = plaintext] head -> n1 n1 -> n2 n2 -> n3 n3 -> tail tail -> null prev -> n1 curr -> n1 next -> n2 } ``` 6. `!(0x02 < 0x02)` 為 true ```graphviz digraph first_insert { node [shape = box] rankdir = LR head [label = "{head | 0x00 |<n> next}", shape = record] n1 [label = "{n1 | 0x02 |<n> next}", shape = record] n2 [label = "{n2 | 0x04 |<n> next}", shape = record] n3 [label = "{n3 | 0x06 |<n> next}", shape = record] tail [label = "{tail | 0xff |<n> next}", shape = record] prev [label = "prev", shape = plaintext] curr [label = "curr", shape = plaintext] next [label = "next", shape = plaintext] null [label = "NULL", shape = plaintext] head -> n1 n1 -> n2 n2 -> n3 n3 -> tail tail -> null prev -> n1 curr -> n1 next -> n2 } ``` 7. delete-1 - 要刪 `0x02` 卻 mark `0x04`,很奇怪 ```graphviz digraph first_insert { node [shape = box] rankdir = LR head [label = "{head | 0x00 |<n> next}", shape = record] n1 [label = "{n1 | 0x02 |<n> next}", shape = record] n2 [label = "{n2(m) | 0x04 |<n> next}", shape = record] n3 [label = "{n3 | 0x06 |<n> next}", shape = record] tail [label = "{tail | 0xff |<n> next}", shape = record] prev [label = "prev", shape = plaintext] curr [label = "curr", shape = plaintext] next [label = "next", shape = plaintext] null [label = "NULL", shape = plaintext] head -> n1 n1 -> n2 n2 -> n3 n3 -> tail tail -> null prev -> n1 curr -> n1 next -> n2 } ``` - 改為 ```c uintptr_t tmp = get_unmarked(curr); if (!atomic_compare_exchange_strong(&curr, &tmp, get_marked(curr))) ... ``` ```graphviz digraph first_insert { node [shape = box] rankdir = LR head [label = "{head | 0x00 |<n> next}", shape = record] n1 [label = "{n1(m) | 0x02 |<n> next}", shape = record] n2 [label = "{n2 | 0x04 |<n> next}", shape = record] n3 [label = "{n3 | 0x06 |<n> next}", shape = record] tail [label = "{tail | 0xff |<n> next}", shape = record] prev [label = "prev", shape = plaintext] curr [label = "curr", shape = plaintext] next [label = "next", shape = plaintext] null [label = "NULL", shape = plaintext] head -> n1 n1 -> n2 n2 -> n3 n3 -> tail tail -> null prev -> n1 curr -> n1 next -> n2 } ``` 8. delete-2 - `prev` 跟 `curr` 在 `__list_find` 一直指向同一個地方,這邊沒辦法做 `delete` - `prev`、`curr`、`next` 命名語意會讓人覺得是三個連續的 `node`,這邊有兩個方案 1. 修改 `__list_find` 演算法,符合命名語意 2. 改用[論文][A_Pragmatic_Implementation_of_Non-Blocking_Linked_Lists]的作法 - 修改 `__list_find` 演算法 - 修改前 ```c static bool __list_find(list_t *list, list_key_t *key, atomic_uintptr_t **par_prev, list_node_t **par_curr, list_node_t **par_next) { atomic_uintptr_t *prev = NULL; list_node_t *curr = NULL, *next = NULL; try_again: prev = &list->head; // curr 應該改成 prev->next 才比較符合命名語意 curr = (list_node_t *) atomic_load(prev); (void) list_hp_protect_ptr(list->hp, HP_CURR, (uintptr_t) curr); if (atomic_load(prev) != get_unmarked(curr)) goto try_again; while (true) { // 功能跟檢查 next == list->tail 重複,這段要拿掉 if (!get_unmarked_node(curr)) return false; next = (list_node_t *) atomic_load(&get_unmarked_node(curr)->next); (void) list_hp_protect_ptr(list->hp, HP_NEXT, get_unmarked(next)); // curr 到 next 中間被插隊應該重試比較合理 if (atomic_load(&get_unmarked_node(curr)->next) != (uintptr_t) next) break; if (get_unmarked(next) == atomic_load((atomic_uintptr_t *) &list->tail)) break; // 應該改成檢查 prev 跟 curr 中間有沒有被插隊 if (atomic_load(prev) != get_unmarked(curr)) goto try_again; // 覺得改成檢查 curr 比較合理 if (get_unmarked_node(next) == next) { if (!(get_unmarked_node(curr)->key < *key)) { *par_curr = curr; *par_prev = prev; *par_next = next; return get_unmarked_node(curr)->key == *key; } prev = &get_unmarked_node(curr)->next; (void) list_hp_protect_release(list->hp, HP_PREV, get_unmarked(curr)); } else { uintptr_t tmp = get_unmarked(curr); if (!atomic_compare_exchange_strong(prev, &tmp, get_unmarked(next))) goto try_again; list_hp_retire(list->hp, get_unmarked(curr)); } curr = next; (void) list_hp_protect_release(list->hp, HP_CURR, get_unmarked(next)); } *par_curr = curr; *par_prev = prev; *par_next = next; return false; } ``` - 修改後 ```c static bool __list_find(list_t *list, list_key_t *key, list_node_t **par_prev, list_node_t **par_curr, list_node_t **par_next) { list_node_t *prev = NULL, *curr = NULL, *next = NULL; try_again: prev = list->head; curr = (list_node_t *) atomic_load(&(prev->next)); (void) list_hp_protect_ptr(list->hp, HP_CURR, (uintptr_t) curr); if (atomic_load(&(prev->next)) != get_unmarked(curr)) goto try_again; while (true) { next = (list_node_t *) atomic_load(&get_unmarked_node(curr)->next); (void) list_hp_protect_ptr(list->hp, HP_NEXT, get_unmarked(next)); // curr 到 next 中間被插隊,重試 if (atomic_load(&get_unmarked_node(curr)->next) != (uintptr_t) next) goto try_again; // prev 到 curr 中間被插隊,重試 if (atomic_load(&get_unmarked_node(prev)->next) != get_unmarked(curr)) goto try_again; // 到 tail 還找不到 if (get_unmarked(curr) == atomic_load((atomic_uintptr_t *) &list->tail)) break; if (get_unmarked_node(curr) == curr) { if (!(get_unmarked_node(curr)->key < *key)) { // curr 沒被 mark 且 curr->key >= key *par_prev = prev; *par_curr = curr; *par_next = next; return get_unmarked_node(curr)->key == *key; } prev = get_unmarked_node(curr); (void) list_hp_protect_release(list->hp, HP_PREV, get_unmarked(curr)); } else { // curr 被 mark,嘗試將 prev->next,指向 next // 若失敗表示 prev 有修改,重試 uintptr_t tmp = get_unmarked(curr); if (!atomic_compare_exchange_strong(&(prev->next), &tmp, get_unmarked(next))) goto try_again; list_hp_retire(list->hp, get_unmarked(curr)); } curr = next; (void) list_hp_protect_release(list->hp, HP_CURR, get_unmarked(next)); } *par_prev = prev; *par_curr = curr; *par_next = next; return false; } bool list_insert(list_t *list, list_key_t key) { list_node_t *prev = NULL, *curr = NULL, *next = NULL; list_node_t *node = list_node_new(key); while (true) { if (__list_find(list, &key, &prev, &curr, &next)) { list_node_destroy(node); list_hp_clear(list->hp); return false; } atomic_store_explicit(&node->next, (uintptr_t) curr, memory_order_relaxed); uintptr_t tmp = get_unmarked(prev->next); if (atomic_compare_exchange_strong(&(prev->next), &tmp, (uintptr_t) node)) { list_hp_clear(list->hp); return true; } } } bool list_delete(list_t *list, list_key_t key) { list_node_t *prev, *curr, *next; while (true) { if (!__list_find(list, &key, &prev, &curr, &next)) { list_hp_clear(list->hp); return false; } uintptr_t tmp = get_unmarked(curr); if (!atomic_compare_exchange_strong(&curr, &tmp, get_marked(curr))) { continue; } tmp = get_unmarked(curr); if (atomic_compare_exchange_strong(&(prev->next), &tmp, get_unmarked(next))) { list_hp_clear(list->hp); list_hp_retire(list->hp, get_unmarked(curr)); } else { list_hp_clear(list->hp); } return true; } } ``` - 結果 ```bash debug info: 0x000000000000 -> 0x55ebf3629060 -> 0xffffffffffffffff debug info: 0x000000000000 -> 0x55ebf3629060 -> 0x55ebf3629068 -> 0xffffffffffffffff debug info: 0x000000000000 -> 0x55ebf3629060 -> 0x55ebf3629068 -> 0x55ebf3629070 -> 0xffffffffffffffff debug info: 0x000000000000 -> 0x55ebf3629060 -> 0x55ebf3629068 -> 0x55ebf3629070 -> 0x55ebf3629078 -> 0xffffffffffffffff debug info: 0x000000000000 -> 0x55ebf3629060 -> 0x55ebf3629068 -> 0x55ebf3629070 -> 0x55ebf3629078 -> 0x55ebf3629080 -> 0xffffffffffffffff debug info: 0x000000000000 -> 0x55ebf3629068 -> 0x55ebf3629070 -> 0x55ebf3629078 -> 0x55ebf3629080 -> 0xffffffffffffffff debug info: 0x000000000000 -> 0x55ebf3629070 -> 0x55ebf3629078 -> 0x55ebf3629080 -> 0xffffffffffffffff debug info: 0x000000000000 -> 0x55ebf3629078 -> 0x55ebf3629080 -> 0xffffffffffffffff debug info: 0x000000000000 -> 0x55ebf3629080 -> 0xffffffffffffffff debug info: 0x000000000000 -> 0xffffffffffffffff inserts = 7, deletes = 7 ``` - 用[論文][A_Pragmatic_Implementation_of_Non-Blocking_Linked_Lists]的作法 list 操作在單一執行緒的執行結果也是對的 ```c static list_node_t *__list_find(list_t *list, list_key_t key, list_node_t **left_node) { list_node_t *left_node_next, *right_node; list_node_t *curr, *curr_next; try_again: do { curr = (list_node_t *) list->head; curr_next = (list_node_t *) ((list_node_t *) list->head)->next; do { if (!is_marked(curr_next)) { *left_node = curr; (void) list_hp_protect_ptr(list->hp, HP_PREV, get_unmarked(curr)); left_node_next = curr_next; (void) list_hp_protect_ptr(list->hp, HP_CURR, get_unmarked(curr_next)); } curr = get_unmarked_node(curr_next); if (curr == (list_node_t *) list->tail) { break; } curr_next = (list_node_t *) curr->next; } while (is_marked(curr_next) || curr->key < key); right_node = curr; (void) list_hp_protect_ptr(list->hp, HP_NEXT, get_unmarked(curr)); /* 2: Check nodes are adjacent */ if (left_node_next == right_node) { if ((right_node != (list_node_t *) list->tail) && is_marked((right_node)->next)) { goto try_again; /*G1*/ } else { return right_node; /*R1*/ } } /* 3: Remove one or more marked nodes */ if (atomic_compare_exchange_strong(&(*left_node)->next, &left_node_next, right_node)) { /*C1*/ list_hp_retire(list->hp, get_unmarked(left_node_next)); if (right_node != (list_node_t *) list->tail && is_marked(right_node->next)) { goto try_again; /*G2*/ } else { return right_node; /*R2*/ } } } while (true); /*B2*/ } bool list_insert(list_t *list, list_key_t key) { list_node_t *new_node = list_node_new(key); list_node_t *next, *prev; do { next = __list_find(list, key, &prev); if (next != (list_node_t *) list->tail && next->key == key) { /*T1*/ list_node_destroy(new_node); list_hp_clear(list->hp); return false; } new_node->next = (uintptr_t) next; if (atomic_compare_exchange_strong(&prev->next, &next, new_node)) { /*C2*/ list_hp_clear(list->hp); return true; } } while (true); /*B3*/ } bool list_delete(list_t *list, list_key_t key) { list_node_t *curr = NULL, *next = NULL, *prev = NULL; do { curr = __list_find(list, key, &prev); if (curr == (list_node_t *) list->tail || curr->key != key) { /*T1*/ list_hp_clear(list->hp); return false; } next = (list_node_t *) curr->next; if (!is_marked(next)) { if (atomic_compare_exchange_strong((list_node_t **) &(curr->next), &next, get_marked(next))) { /*C3*/ break; } } } while (true); /*B4*/ if (atomic_compare_exchange_strong((list_node_t **) &(prev->next), &curr, next)) { /*C4*/ // curr = __list_find(list, curr->key, &prev); list_hp_clear(list->hp); list_hp_retire(list->hp, get_unmarked(curr)); } else { list_hp_clear(list->hp); } return true; } ``` - 改回多執行緒環境測試 - 執行結果 ```bash inserts = 4098, deletes = 4098 ``` - 一些想法 1. 不確定自己改的 `__list_find` 是否正確,還是只是數字剛好? 2. benchmark - Harris 版本 - 自己的版本 ##### TODO - [ ] 改進 hazard pointer 操作 讀[論文][Lock-Free_Data_Structures_with_Hazard_Pointers]看看 `hazard pointer` 哪邊可以改進 - [ ] 測試對齊寬度的影響 - 同學 [9m77fans][9m77fans_2021q3_homework2_hp] 的有提到 > 一般我們解決false sharing都是將資料對齊一個cache line就夠了,這邊卻是對齊兩個,目前我是只有看到folly這套facebook的函式庫有這樣做,它註解中寫到這是他們實驗的結果,兩個cache line對齊再跟atomic變數操作時效能比較好 ### 3. 對比 rcu_list,解釋同為 lock-free 演算法,跟上述 Hazard pointer 手法有何異同?能否指出 rcu_list 實作缺陷並改進? :::info 施工中 ::: ## 參考資料 1. [A Pragmatic Implementation of Non-Blocking Linked Lists][A_Pragmatic_Implementation_of_Non-Blocking_Linked_Lists] 2. [Lock-Free Data Structures with Hazard Pointers][Lock-Free_Data_Structures_with_Hazard_Pointers] [linux2021-summer-homework2]: https://hackmd.io/@sysprog/linux2021-summer-homework2 [RinHizakura_2021q3_homework2_hp]: https://hackmd.io/@RinHizakura/S1WCkafJY#%E9%8C%AF%E8%AA%A4%E4%BF%AE%E6%AD%A3%E8%88%87%E7%A8%8B%E5%BC%8F%E6%94%B9%E9%80%B2 [9m77fans_2021q3_homework2_hp]: https://hackmd.io/@9m77fans/sysprog2021q3-hw2#link-list-API [A_Pragmatic_Implementation_of_Non-Blocking_Linked_Lists]: https://www.cl.cam.ac.uk/research/srg/netos/papers/2001-caslists.pdf [Lock-Free_Data_Structures_with_Hazard_Pointers]: https://erdani.org/publications/cuj-2004-12.pdf