contributed by < LindaTing0106
>
看完此篇文章不經讓我思考,其實很多現在在我們日常中隨手可見的物品,一定也是經過前人不斷失敗,再不斷嘗試,最終才成為改善我們生活品質的物品。我想這也恰恰是老師從課程一開始就一直跟我們講的事情:「要誠實面對自己。」,正是因為可以誠實面對自己,才可以坦然接受失敗,再從失敗中改進並且學習。
其中 int : 0;
會導致 c 和 d 應該去對齊下一個 4 bytes ,也就導致 c 和 d 不是存取到 i 的地址,而是存取到其他地址,故每次執行時的值也會不一樣。
其中提到的 in-place string reverse 想法:一直 swap '\0'之前的character 。但在描述演算法處,在把頭尾互換之後,需要再把尾端和 '\0' 互換,重複以上步驟直到 '\0' 至於字串的中間,這裡不太理解的是為什麼不能直接互換頭尾,直到頭端位置大於等於尾端,為什麼要去動到 '\0' ?
如果改成下面這種形式,則可以減少在每次迴圈時需要先將 i1 和 i2 相加步驟。
但若考慮到這樣寫 foo(&var, &var, &var) 來呼叫 foo() ,也就是在傳入的三個參數的地址為一樣的情況下,這兩段程式碼的執行結果則會天差地遠。
先假設 var = 1
*res += *i1 + *i2
後 *res 會等於 3 ,而由於這三個引數的地址相同,則 *i1 和 *i2 的值也會是 3 ,故下一次運算後 *res 則變為 9 ,以此類推。*res += *i1 + *i2
後 *res 會等於 3 ,而由於這三個引數的地址相同,則 *i1 和 *i2 的值也會是 3 ,但由於 tmp 已經把最一開始 *i1 和 *i2 的值相加並存取下來,故之後每次運算其實只是在對 *res += 2。由於上述兩種情況對於運算的結果有極大的不同,所以此時編譯器不會對此程式碼做最佳化。
編譯器可刪去沒在使用的 static global variable 以節省空間,但不能刪去 (目前) 沒在使用的 non-static global variable,因為無法確定其他的 Compilation Unit 是否會用到此變數
這是為何建議 local function 要宣告成 static 的用意!
算術位移的應用,若要判斷一個 int 型態的變數 n 是否為正數,可用
n >> 31
其等價於n >=0 ? 0: -1
這是利用在編譯器中右移往往採用算數位移的關係,將負數向右位移 31 bit 後,即該數變為 或是 。
若 n 是 32-bit 整數,那麼
abs(n)
等同於((n >> 31) ^ n) - (n >> 31)
TODO: 閱讀 並行程式設計: 實作輕量級的 Mutex Lock 並重現實驗,紀錄問題
TODO: 閱讀 https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2023/SPIN.pdf | https://github.com/mc-imperial/modelcheckingfutexes 重現實驗 (原本用 C++) 並紀錄問題
TODO: 用 C11 futex 重寫 https://github.com/mc-imperial/modelcheckingfutexes/tree/main/cpp 程式碼
Q : 第三周的字串反轉範例,為什麼一定要和字串結尾的 '\0' 做更改呢?
A : 這是某間公司的面試題目,是為了考驗面試者能不能在 in-place 的限制下,將字串反轉,其實一般字串反轉也不是一定只能這樣實作,但這就只是面試規定。
Q : 在 lab0 中,希望我們將 tic-tac-toe 加入作業中,並且加入 ai vs ai 模式和處理鍵盤事件,我發現許多人都是使用搶占式的方式加入,所以我自己是使用協同式的方式,但結果發現使用協同式會導致每個 task 都需要等待一段時間才會開始工作,所以想問老師這個作業是其實一定要使用搶占式的模式嗎?另外如果使用起來搶占式的運作比較流暢,那為什麼還需要有協同式的存在呢?
A : 此作業的目的在於希望同學可以試著將一段程式加入多工運作,因此只要有加入都可以,但程度較好的同學當然可以在做改進,但至少應該要做到加入多工這件事。另外像 lab0-c 中的網路伺服器則適合使用協同式的方式運作,因為他的執行路徑明確,不會一件事做到一半突然要去做其他事。
preempt (搶佔)
lab0-c 內建網頁伺服器: 單工 (執行路徑明確)