一、VSCode安裝及環境配置
初始在Win下安裝Mingw-w64/GCC 和 GDB,在VSCode下打開項目案例,發現在linktable中需要包含pthread頭文件。此文件是基於Linux系統環境下的頭文件,對應win系統環境下的window.h頭文件。所以,本人為了方便后續操作方便,改在Ubuntu下進行項目案例分析。
進入Ubuntu,在Ubuntu軟件中搜索安裝VSCode;VSCode中下載安裝C/C++環境插件;打開對應項目案例文件夾。首先查看Makefile文件:
這里make all指令表示執行后會編譯文件夾下的.c文件。
在VSCode終端下運行make all,編譯生成了對應的三個.c文件的.o文件,因為Makefile里沒有添加對其他三個test_.c的操作,所以當前是不能指令執行這三個c文件。
在終端下運行make clean,刪除了生成的原本的三個.o文件
終端下運行./test
輸入已實現的cmd命令名,這里補充了fork、exec和quit指令操作
二、分析代碼的藝術
1.程序塊頭部注釋
這里標明了代碼語言以及該文件的作用,模塊的對外接口,方便自動生成開發者文檔。
2.模塊化軟件設計
模塊化是在軟件系統設計時保持系統內各部分相對獨立,以便每一個部分可以被獨立地進行設計和開發。這個做法被的基本原理是關注點的分離。在此編程項目中也體現到了關注點的分離,首先來看耦合:總體代碼文件分成linktable、menu、test三大類,分別實現的是程序接口結構設計、命令菜單解析命令操作以及測試文件。前兩類有細分成了.c文件和.h文件,.h文件存放功能實現函數的聲明、.c文件存放功能實現函數的定義。這樣兩兩文件又有着聯系,命令菜單解析命令操作需要接口結構來體現,測試文件需要基於他們來實現具體案例。然后來看內聚,分為三大類,分別實現不同的功能就是內聚的體現。KISS原則即一行代碼制作一件事、一塊代碼只做一件事、一個函數只做一件事、一個模塊只做一件事。
3.可重用軟件設計
首先考慮Consumer Reuse和Produce Reuse(消費者重用和生產者重用),Consumer Reuse重在重用已有的一些軟件模塊代碼,以加快項目工作進度。比如說最常見的max()、min()的實現,每次在需要輸出最大最小數值時,都要重寫一遍。如果把這些思想用一個模塊封裝在一起,這樣每次使用,只需短短一行即可。在本menu案例中,如下函數都是消費者重用的體現
Produce Reuse重在設計可重用軟件的設計,大致需要注意幾個因素:通用模塊、通用接口並有清晰完善的定義描述、清晰一致的命名規則等。本案例中在.h文件中即是生產者重用的體現:
每個函數都有一個直觀的函數名,以及參數名,在聲明結束后會通過注釋的方式給出對用到的數據結構和算法的清晰的文檔描述。其次是軟件模塊接口的實現藝術,首先理解函數的接口規格,主要體現callin和callback兩個函數方式的接口,如上圖的CreateLInkTable、AddLinkTableNode以及DelLinkTableNode三個函數,均給出了callin接口的需要的參數類型和參數名,並且從函數名和參數名就可以很直觀的看出其實際的意義。圖中最后一個函數擁有一個特殊的參數成員:
這是一個函數,SearchLinkTableNode函數在執行過程中,通過把具體任務傳遞給condition函數來讓他查詢目標,這里參數名更改為args間接使上層用戶隱藏了對底層人員的信息泄露,其中condition函數的定義如下。可以看到,在函數體內,才會使用cmd這個參數,也就起到了封裝信息的作用。
4.可重入函數和線程安全
上面有說到消費者重用規則,所以在多個線程使用同一函數時,可以會因為不同的訪問順序導致輸出一個錯誤的答案。比如一個函數初始化一個a值為1,然后對它執行++操作。現在我們假設有這樣一種調用順序,甲線程先執行初始化操作,然后執行++操作。這個時候有一個乙線程剝奪資源然后執行++操作,然后就會得到一個錯誤的a值。在本案例中有相應的隱患也有對應解決代碼。
引入Linux下的pthread線程頭文件。這個DelLinkTableNode函數是實現在一個LinkTable中刪除一個結點,首先判斷此鏈表是否存在,存在的話分兩種情況分別設置線程鎖,然后執行相對應的操作。最后在執行完畢后將線程解鎖,其他重入操作就可以執行了。可以看到,在此過程中,只有當某一個線程完全執行結束,下一個才可以執行。線程安全問題都是由全局變量及靜態變量引起的。如上的pLinkTable.若每個線程中對全局變量、靜態變量只有讀操作而無寫操作,一般來說,這個全局變量是線程安全的。
以上源代碼來自項目案例https://github.com/mengning/menu