https://avatars.githubusercontent.com/u/42119758?v=4

davidlei blog

sudo go: command not found 問題解決

這問題算是一個小坑,每次開新的虛擬機或者建環境的時候都會遇到(然後每次都忘記解決方式跑去google),所以在這邊紀錄一下解決方式 /etc/sudoers 在用 sudo 下指令時,系統會從 /etc/sudoers 這個文件來獲得環境變數,根據那些路徑去找指令的執行檔案在哪,所以我們需要把 /usr/local/go/bin 放到 /etc/sudoers 裡面,讓系統知道 go 指令要去哪執行 /etc/sudoers 裡面有個 secure_path,把 usr/local/go/bin 加到那個字串即可.

從執行順序來探討 Race condition, go 語言的 happens-before 規則

同步處理(Synchronization) 確保多個執行單元同時存取某些資源的時候,執行結果不會因為執行單元的時間先後導致發生不可預期的錯誤。 Linux kernel 提供了很多協助處理 Synchronization 問題的機制,如果不在 Concurrency 的架構內使用適當的同步技術,就可能會引發 Race condition 的問題。 可以參考 Concurrency in the Kernel 來快速了解 kernel 內對於 Concurrency 提供了什麼樣的工具。 Race condition 在一組執行單元(process/thread)以 shared memory 的方式進行資料共享或者溝通時,因為沒有對於共享變數提供互斥存取(mutual exclusive access)的處理,可能會導致執行單元之間因為交錯執行,導致最後的結果不如預期。 底下用一個簡單的例子來說明 race condition 造成執行結果不如預期的情況。 #include <thread> #include <iostream> const int thread_num = 20000; void func(int &count) { count = count + 1; } int main() { int count = 0; std::thread threads[thread_num]; for (int i = 0; i < thread_num; ++i) threads[i] = std::thread(func, std::ref(count)); for (auto &th : threads) th.

Concurrency vs Parallelism 淺談兩者區別以及名詞介紹

前言 最近在複習 jserv 老師的並行與多執行緒程式設計,一開始介紹了兩個常常被混淆的名詞,Concurrency 與 Parallelism,每次感覺懂了,過一陣子要我清楚的說明又有點講不太清楚,所以來寫一篇筆記紀錄一下。 裡面有些說法跟圖片是參考 jserv 老師的講座,裡面內容非常精彩,有機會的話一定要挑戰看看! Concurrency(並行) vs Parallelism(平行) 常被混淆的原因不只是因為兩個單字的中文翻譯很像,而且兩者在觀念上也有重疊的部份,所以一開始很難去分清楚這兩者的差異。 Concurrency 通常用來描述程式的架構,將程式的功能拆成多個不同且獨立運行的模組或稱為工作(Task),Parallelism 則是強調同時執行多個程式,底下會詳細舉例說明兩者的差異。 Concurrency 把程式功能拆分的小的 Task 後,如果同時運作,就可以說 Concurrency 有用到 Parallelism,所以不一定要用 Parallelism 才能達到 Concurrency 的目的。 Concurrency 只有強調把程式拆開成多個可獨立執行的模組,但沒有強調這些拆開的模組一定要同時執行。 Parallelism 更強調的是同時的概念,不同的任務可以分配給不同的硬體,同一時間會有多個任務一起同時執行。 所以講到 Concurrency 偏向討論在程式架構上,把一個任務拆成多個可獨立執行的子任務,Parallelism 則討論規劃怎麼分配資源的議題,讓多個子任務可以同時執行。 單一 cpu 的 Concurrency 在以前的年代,或者一些資源受限的環境下,可能運算資源只有單個 cpu,這時候如果有多位使用者想同時使用這台電腦就必須要營造出 Concurrency 的感覺,讓每個使用者都覺得自己使用了這個電腦的全部資源。 底下的 jserv 老師上課給的範例 可以看到在單一 cpu 的場景,意味著同一時間只能有一個任務被執行,所以硬體需要在不同任務之間快速切換,在人類的角度,每個電腦的使用者都覺得自己有著所有的資源,但其實只是切換的速度很快,讓使用者有種錯覺。 以暗殺教室的殺老師為例,先不用講詳細的設定,在漫畫中有一幕場景,殺老師想要為底下的學生每個人量身打造上課的教材,但是上課時是固定的,這時候顯然殺老師有修過 Linux 核心設計,所以知道在單核的情況下只能透過快速的切換讓底下每位學生在體感上都上滿一整節課,示意圖如下 找不到上課的素材,只能用體育課的快速切換當示意圖 因為殺老師只有單一個體,所以可以視作單一 cpu,在不同使用者之間快速切換,這樣就可以說他是 Concurrency,但是不能稱為 Parallelism,不能稱為 Parallelism 是因為即使移動的再快,都不符合同時的要求。 那動漫界最適合解釋 Parallelism 的角色是誰呢? 當然是火影忍者的漩渦鳴人了,他的招牌多重影分身之術就很適合拿來解釋 Parallelism 的概念。 在設定上,多重影分身中每個分身都是有實體的存在,如果每個分身同時進行著某個任務的話,我們就可以說符合 Parallelism 的概念。 今天如果鳴人在寫作業,總共有10題,他叫了九個分身,大家一起完成作業,所以一個大的任務(作業)拆成10個子任務(每一個小題),而且十個人同時去完,這樣就同時符合 Concurrency 跟 Parallelism 的定義了。

資料庫 ER Model(一): Entity 與 Attribute

收集到 Requirements 最難,很難提出"精準"的需求 Entity entity 是 RDBMS 中實際的資料實體,可以用程式的概念理解,定義好 struct 之後一定會在某個地方建立一個實體,裡面會根據 struct field type 去存放資料。 type student struct { name string age int } func main() { studentA := student{"david", "20"} } studentA 就可以視為一個 entity,擁有真正資料的實體。 Attribute attribute 描述 entity 的屬性,拿上面 student 的例子,name, age 都可以當作 attribute。 在資料庫內 attribute 分成很多不同類型,大致可以分成 Simple, Composite, Multi-valued。 Simple Simple attribute 通常指那些無法繼續再分割的 field,對應到程式語言可以理解成基本的 data type,像是 student 的 age 就是單純的 int。 Composite Composite attribute 是由多個不同的部份組成一起的概念,像是外國的名字可能有 FirstNAme, MiddleName, LastName 等等

leetcode 1022. Sum of Root To Leaf Binary Numbers [Easy]

題目敘述 Input: root = [1, 0, 1, 0, 1, 0, 1] Output: 22 Explanation: (100) + (101) + (110) + (111) = 4 + 5 + 6 + 7 = 22 給一個節點為 0 或者 1 的 binary tree,回傳從 root 為起點到各個 leaf 節點路徑組成二進位數的合。 解題紀錄 利用 DFS 去尋訪,如果 !root->left && !root->right 就代表到達 leaf,直接回傳算出來的值。 class Solution { public: int sumRootToLeaf(TreeNode* root) { return solution(root, 0); } int solution(TreeNode *root, int bin) { if (!

Linux waitqueue 原始碼解讀

本文章環境基於 Linux v4.14.259 概述 waitqueue 如同其名,是 kernel 中管理一些在等待資源的 task 的資料結構,在 task 還沒辦法獲得資源時,會先將其放入 waitqueue 等待特定條件或者資源準備就緒才會把該 task 喚醒。 waitqueue 有定義兩種資料結構 wait_queue_head: waitqueue 的 head wait_queue_entry: 來表示每個在 waitqueue 的元素 waitqueue 所有的實現都是基於 kernel 內建的 double circular linked list 來實現,所以本身的設計非常簡潔。 以下為 waitqueue 基本的 data struct 定義,位在 /include/linux/wait.h wait_queue_head_t struct wait_queue_head { spinlock_t lock; // 自旋鎖 struct list_head head; // 指向 prev, next entry. }; typedef struct wait_queue_head wait_queue_head_t; 初始化 waitqueue 要建立新的 waitqueue,必須要先初始化 wait_queue_head_t 結構,透過 init_waitqueue_head,定義如下