從作業系統核心看設計模式--linux核心的facade模式
linux的核心當中處處充滿了設計模式,本文先討論一下外觀模式。外觀模式就是將客戶和子系統解耦,為客戶將複雜的子系統進行封裝,從而使得客戶可以使用簡單易用的介面。
眾所周知,linux和unix是十分的相似以至於很多人都把linux當作unix的一種,實際上他們一點也不同,一個linux程式設計師可以毫不費力的 轉到unix下程式設計不是因為這個人水平多高,而是因為linux和unix遵循了幾乎相同的介面,而程式設計師只需要和介面打交道,所以一切變得容易,這種接 口在某種意義上可以認為就是posix。
我來說一下linux核心中用到外觀模式的一些例子。
1.檔案讀寫介面
考慮一個讀檔案的過程,必須有檔名,然後有檔案儲存的介質,這樣才可以將檔案讀出,使用者要使用這種方式讀檔案的話,就必須自己動手去訪問磁碟,顯然就要對磁碟很瞭解,這是不現實的,這個過程起碼涉及到快取管理子系統,磁碟儲存子系統,但是linux並沒有苛求使用者去直接操作這兩個子系統而是為之代勞了,提供給使用者的就是簡單的,容易理解的read和write還有上述二者之前的open。外觀模式使得子系統的更改不用通知使用者,linux核心做到了,從 0.01到2.6.27,要讀一個檔案幾乎都是在用一樣的介面,但是底層的子系統實現卻更變了很多,幾乎一次又一次得被重寫,使用者一點也沒有感覺到(當然能被感覺到,比如速度快了,所以這裡的使用者指的是程式設計師程式設計的過程)。好了,使用者層的我們說完了,那麼進入了系統,看以下程式碼:
asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, size_t count)
{
...
ret = vfs_write(file, buf, count, &pos);
...
}
第四行的vfs_write裡面呼叫了具體檔案系統的file_operations的write方法,這又是一個外觀,可以這麼說,一直到最底層的磁碟,外觀模式一直在起著用,這樣就使得一個系統作為客戶只需要和這個外觀互動而不用管這個外觀之下到底是什麼。
2.等等等等
我為何如此不負責任呢?不是不負責任,而是根本沒有辦法再寄一個具體的例子了,通讀原始碼,你會發現所有的子系統和該子系統用到的孫系統,在這一棵核心大樹下,都在使用外觀模式,比如缺頁中斷處理只是呼叫通用的缺頁入口程式,具體怎麼處理缺頁就涉及到不同的子系統是怎麼實現的,通用處理作為客戶就此撒手將任 務交給這個外觀,然後等待結果;再比如記憶體分配;還有網絡卡的流量控制;還有磁碟排程;....
外觀模式重要的不是介面本身而使介面如何設計,如何將使用者對若干子系統的互動進行彙總從而實現一個彙總後的操作,該操作可以代替那若干個操作,這在很多時候是一種提取公因子的操作,而在另一些時候缺失一個定限的工作,比如核心根本不允許的操作不能放到這個“外觀”中,當然可以反著理解,如果你不希望核心的 “外觀”干涉你的事物,那麼就不要把你的事物放到和這個外觀關聯的子系統內,因為外觀模式中,外觀是明確定限的。舉個例子可能會好一些,linux核心的 記憶體回收策略是lru,核心會定期檢查規定好的lru連結串列然後將一些位於其上的記憶體釋放掉,這裡的外觀就是核心的回收策略,而子系統就是lru連結串列,如果你不想核心釋放你的記憶體,那麼很簡單,不要將你的記憶體頁面加入到lru連結串列就可以了,核心中是嚴格模組化的,高度低耦合的,往往一個外觀只和確定的子系統互動。