# 2022q1 Homework5 (quiz5) contributed by < [cyrong](https://github.com/cyrong) > ## 測驗1 ## 測驗2 這個程式有兩個主要的結構體 `hp_t` 和 `domain_t` `hp_t` 也就是 hazard pointer 的本體,用來指向需要被保護的資料 `domain_t` 是在每個 thread 中存放所有 hazard pointer 的結構,其中包含了 hazard pointer(s) 和 retired list 而還有一個結構體 `config_t` 是被共用的資源的結構 ```c typedef struct { unsigned int v1, v2, v3; } config_t; static config_t *shared_config; ``` `shared_config` 是被 hazard pointers 共用的資料 ```c typedef struct { hp_t *pointers; hp_t *retired; void (*deallocator)(void *); } domain_t; static domain_t *config_dom; ``` `config_dom` 是每個 thread 中管理 hazard pointer(s) 和 retired list 的結構 ```c static void *reader_thread(void *arg) { (void) arg; for (int i = 0; i < N_ITERS; ++i) { config_t *safe_config = (config_t *) load(config_dom, (uintptr_t *) &shared_config); if (!safe_config) err(EXIT_FAILURE, "load"); print_config("read config ", safe_config); drop(config_dom, (uintptr_t) safe_config); } return NULL; } ``` reader thread 執行兩個函式 `load` 和 `drop` ```c /* * Load a safe pointer to a shared object. This pointer must be passed to * `drop` once it is no longer needed. Returns 0 (NULL) on error. */ uintptr_t load(domain_t *dom, const uintptr_t *prot_ptr) { const uintptr_t nullptr = 0; while (1) { uintptr_t val = atomic_load(prot_ptr); hp_t *node = list_insert_or_append(&dom->pointers, val); if (!node) return 0; /* Hazard pointer inserted successfully */ if (atomic_load(prot_ptr) == val) return val; /* * This pointer is being retired by another thread - remove this hazard * pointer and try again. We first try to remove the hazard pointer we * just used. If someone else used it to drop the same pointer, we walk * the list. */ uintptr_t tmp = val; if (!atomic_cas(&node->ptr, &tmp, &nullptr)) list_remove(&dom->pointers, val); } } /* * Drop a safe pointer to a shared object. This pointer (`safe_val`) must have * come from `load` */ void drop(domain_t *dom, uintptr_t safe_val) { if (!list_remove(&dom->pointers, safe_val)) } ``` `load` 為取值 `prot_ptr` 後將此 `val` 放進 `dom` 中的 hazard pointer list ,首先先找沒有使用的 node 若沒有找到則建立一個新的 node `drop` 為將已經是 safe 的 `val` 從 hazard pointer list 中設定為 0,在這之後可以給其他需要放進 `dom` 的值使用 而在 reader thread 中是 load `shared_config` 後 `print_config` ,接著 drop 此 val writer thread ```c static void *writer_thread(void *arg) { (void) arg; for (int i = 0; i < N_ITERS / 2; ++i) { config_t *new_config = create_config(); new_config->v1 = rand(); new_config->v2 = rand(); new_config->v3 = rand(); print_config("updating config", new_config); swap(config_dom, (uintptr_t *) &shared_config, (uintptr_t) new_config, 0); print_config("updated config ", new_config); } return NULL; } ``` writer thread 為建立新的 `config_t` `new_config` 後將其與 `shared_config` 進行對調 而在進行對調後函式 `swap` 會呼叫 `cleanup_ptr` ,用以釋放 (呼叫 deallocator) 舊的值,而如果還有 reader 正在使用舊的值,則等待至沒有任何 reader 使用後釋放 `swap` 中根據 `flags` 來分別不同的實作 `flags & DEFER_DEALLOC` $\neq$ 0 : 不進行等待,只在當下沒有任何 reader reference 時進行釋放,否則等待到下次 cleanup 被呼叫 `flags & DEFER_DEALLOC` $=$ 0 : 等待至沒有任何 reader reference 此 pointer 後釋放