# 2024q1 Homework5 (assessment) contributed by < [`pao0626`](https://github.com/pao0626) > ## 閱讀〈因為自動飲料機而延畢的那一年〉的啟發與課程感想 在多次創業失敗後,作者選擇製作自動飲料機,這啟發了我對人生常處十字路口的看法。正如我過去和現在經常面臨的抉擇,我們應該抓住機會,勇於實踐而非空想。只有親自動手,我們才能理解失敗的原因,體會其中的經驗。製作飲料機的過程讓我認識到,很多市面上的產品雖然看似簡單,但實際操作和了解其背後原理卻非常困難。這與我作為資訊領域學生的經歷相似。每天雖使用<s>操作系統</s> 作業系統,也曾自認了解其原理,但真正實作時,例如在 Linux kernel 中處理合併排序,我才意識到即使排序的時間複雜度為 $O(n\log{n})$ ,效率的差異仍然顯著,還需考慮到快取的使用。 進入課程第五週後,我深感自己累積了許多課程債需要清償。即使預留了完整一學期的時間來挑戰,進度仍嚴重落後。觀摩同學的作業,看他們如何設計實驗來驗證想法做到真正有效使用程式碼解決問題,甚至還能<s>優化</s> 改良程式碼,這些都讓我直面自己的不足,儘管受到長久的填鴨式教育遺毒,我還是無法完全「誠實面對自己」,仍過分關注考試成績和作業的表面完成度,但我感覺到我的心態正在逐漸改變。雖然目前挫折感很重,但學習過程中的進步也是顯著的,這也在最近的頻繁面試中給予了我很大的幫助。例如,我學會了什麼是前置處理器和巨集(程度就是如此誇張)、使用 Valgrind 進行<s>內存</s> 記憶體檢查,指標的應用和更熟練地使用 Git 進行版本控制。原本我因為擔心錯過當前的面試機會,希望能兼顧學業和面試。但經過一段時間考量後,我意識到無法兩者兼顧,接下來的幾個月我將暫停面試,<s>全力以赴</s> 期許自己能跟上課程進度,因為從理解到應用教材確實需要投入全部的精力。 :::danger 注意用語!見[資訊科技詞彙翻譯](https://hackmd.io/@sysprog/it-vocabulary)和[詞彙對照表](https://hackmd.io/@l10n-tw/glossaries)。 > 經過 GPT 潤飾後沒有仔細檢查,已更改 避免急著說「全力以赴跟上課程進度」,改用事實來印證你的決心。這社會太浮躁,許多時間取巧者備受尊崇,但顯然在這門課中,僅有小聰明是全然不足的。 > 完全就是我的寫照 ::: ## 課程教材和 CS:APP 3/e 心得和提問 ### CS:APP 3/e 心得: :::danger 注意書寫規範! 留意各式細節是讓你在邁向專業的過程中,相當關鍵的素養。 ::: 我複習二補數表示法並深入了解其背後的原理。例如,過去我學習時常常機械記憶 Sign Extension 的規則——對於有符號數字可以直接在最高位加上符號位。而只要實際理解其背後原理後,不難發現這個規則非常合理。我也重溫了一些特別的注意事項,如負數使用右移位時應先增加一(以實現正確的除以 2 效果),以及 `-INT_MIN` 等於 `INT_MIN` 的情況。此外,我複習了浮點數的表示方法,其中包括老師課程中提到的將整數以浮點數形式表示可能出現的錯誤,以及常見的四捨五入方法。 我還預習了一些內容,學到了一個有趣的指令 `leaq` 。結合使用 `leaq(%rdi, %rdi, 2), %rax` 和 `salq $2, %rax` 兩個指令可以實現將 rdi 暫存器的值增加到 12 倍後<s>賦值</s> 傳遞給 rax 暫存器。這不僅加深了我對指令功能的理解,也提升了我的實際應用能力。 :::danger "assign" 是你中學英語就接觸到的詞彙,你的英語老師用「賦值」解釋過該單字嗎?上文該用「指派」或「傳遞」。以流暢的漢語書寫,注重辭彙脈絡與語境。 > 確實沒有 ::: ### [你所不知道的 C 語言: linked list 和非連續記憶體](https://hackmd.io/@sysprog/c-linked-list#%E6%A1%88%E4%BE%8B%E6%8E%A2%E8%A8%8E-Leetcode-2095-Delete-the-Middle-Node-of-a-Linked-List) 心得: 如果早點讀熟此篇章,我想無論是在寫 lab-0 或是面試應該都能輕鬆許多吧。過往一直逃避<s>指針的指針</s> 指標的指標寫法,覺得很不直觀,直到讀完這篇才發現並沒有想像中的困難,而且極具藝術,文中附上的圖片說明更是讓我豁然開朗。 :::danger 注意用語,此處是「指標」 > 已更改 ::: 問題: 1. 想了解為什麼在介紹 `deleteMiddle` 時不保留 void 的優雅寫法如下: ```c void deleteMiddle(node_t **head) { if (!(*head)->next) return; node_t **indir = head; for (node_t *fast = *head; fast && fast->next; fast = fast->next->next) { indir = &(*indir)->next; } node_t *tmp = *indir; *indir = (*indir)->next; free(tmp); } ``` > 起初只是配合 LeetCode 提出的函式原型,才有文中的寫法,你可修改教材筆記,加入介面的改進。 :notes: jserv > 以這個出發點來說我覺得很合理,感覺確實不好做更動 此外,文中介紹的兩種寫法中,其中一種加了 `if (!(*head)->next) return;` 的判斷,一種沒有。是否該統一面臨只有單一節點時是否要進行刪除的作法。 > 應該如此!編撰教材的時間範圍較大,因此難確保程式碼風格一致,而且 LeetCode 規範的介面不夠好 (硬是將 C++ 對應到 C),致使舉例很彆扭。 :notes: jserv > 了解! 後來仔細閱讀後發現有補上 `if (!(*head)->next) return;` 判斷式的程式碼都是必要的,為了避免 `prev->next` 出錯,因此就不做更改了。 2. 在介紹 `mergeTwoLists` 時用了 `*ptr = (struct ListNode *)((uintptr_t) L1 | (uintptr_t) L2);` 取代 `*ptr = L1 ? L1 : L2;` ,想了解其特殊之處。 > 善用 `gcc -S` 觀察輸出的組合語言指令序列。 :notes: jserv > 收到,之後用 gcc -S -fverbose-asm -O0 觀察看看 3. 關於 `#define maxint(a,b) ({int _a = (a), _b = (b); _a > _b ? _a : _b; })` 我寫了一個測試檔案如下,但輸出卻不會是 10 ,閱讀過 [statement expression](https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html) 後得知 variable shadowing 問題,但還是無法理解,我覺得應該會發生重複宣告的問題才對,但實際上還是能印出值,產生亂數但大部分又能穩定輸出 0。 ```c #include <stdio.h> #define maxint(a,b) ({int _a = (a), _b = (b); _a > _b ? _a : _b; }) int main() { int _a = 5; int _b = 10; int c; c = maxint (_a, _b); printf("Result: %d\n", c); return 0; } ``` > 對照 [Linux 核心原始程式碼巨集: max, min](https://hackmd.io/@sysprog/linux-macro-minmax) :notes: jserv 4. 介紹 `circular linked list` 時,程式碼中的註解 `// lambda is length` 我認為應該改成 `// lambda is cycle length` 更為貼切。 此外在 `get meet point` 函式裡, `while (hare && tortoise)` 也確實應該改成 `while (hare && tortoise && (hare != tortoise))` 才對。 ### [你所不知道的 C 語言:記憶體管理、對齊及硬體特性](https://hackmd.io/@sysprog/c-memory#glibc-%E7%9A%84-mallocfree-%E5%AF%A6%E4%BD%9C) 問題: 1. 在 glibc 的 malloc/free 實作中介紹 Fast Bin 時提到其不執行合併,但後面介紹 malloc 流程時卻說會合併 fastbin,無法理解這部分。 ### [並行程式設計: Atomics 操作 -- 案例探討 SPSC](https://hackmd.io/@sysprog/concurrency/%2F%40sysprog%2Fconcurrency-atomics#wait-free-amp-lock-free) 問題: 1. 文中提及`生產者會先更新 r->cons.head 到生產結束後的 index 位置,直到核心的生產操作 ENQUEUE_PTRS() 結束,再把 r->cons.tail 也一併更新成生產完成後的 index 位置。`我認為應該是 r->prod.head 和 r->prod.tail 才對? 此外根據程式碼片段: ```c uint32_t prod_next = prod_head + n; r->prod.head = prod_next; /* write entries in ring buffer */ ENQUEUE_PTRS(); __compiler_barrier(); r->prod.tail = prod_next; ``` 文中內容`當 r->cons.tail 和 r->cons.head 在某個執行的時間點有差異,兩個變數之間的範圍表示「生產者正在存取的有效 buffer 範圍」`也應該是 prod 才對嗎? (我有直接更改 hackmd 但被老師改回來了:cry:,如果老師有空能回答我理解錯誤的盲點會很感謝老師) ### [The Linux Kernel Module Programming Guide](https://sysprog21.github.io/lkmpg/#sysfs-interacting-with-your-module) 問題: 1. 文中在第 8 章提供的範例中,設定權限的程式碼如下: ```c static struct kobj_attribute myvariable_attribute = __ATTR(myvariable, 0660, myvariable_show, (void *)myvariable_store); ``` :::danger 注意用詞: * file 是「檔案」,而非「文件」(document) > 沒查閱[詞彙對照表](https://hackmd.io/@l10n-tw/glossaries)是我的疏失 ::: 因此使用者試圖存取<s>文件系統</s> 檔案系統中此模組檔案時應該使用 sudo 才對? 命令改變如下: ```shell sudo cat /sys/kernel/mymodule/myvariable ``` ```shell sudo sh -c 'echo "32" > /sys/kernel/mymodule/myvariable' ``` 或是將範例中 `__ATTR(myvariable, 0660, ...);` 的權限設置放寬為 0666。 :::warning 提交 pull request! > 好的 ::: ### [simrupt](https://github.com/sysprog21/simrupt)專案 問題: 1. 註解 `skip oldest element if kfifo buffer is full` 是否改成 `skip newest element if kfifo buffer is full` 更恰當呢?或是我的理解有誤,詳見 [issue](https://github.com/sysprog21/simrupt/issues/3)。 ## 想投入的專案 1. 想補上 ttt 的實作 2. 補上所有作業 3. (重做 lab0 並彙整學員成果 / 位元操作 / 紅黑樹實作改進) LKM TODO: 看 Homework6 (simrupt) TODO: evaluation ## 目前進度 看完 Homework6 中複習 C 語言的大部分內容,包括數值系統, bitwise 操作, List API, alignment。補上之前沒跟上的課堂進度,並概略的撰寫了[筆記](https://hackmd.io/cBBR-_e5Skm1G7ipGSD0QQ?both)方便自己回憶。 進度更新[於此](https://hackmd.io/exy39om0TrqsAQC_lklwbg) (6/22更新) p.s. 如果我想新增使用者名稱,讓我的HackMD網址更加簡潔,是否會影響我先前提交的所有作業呢?