2013年4月8日 星期一

Data Hiding 的兩種作法: Pimpl 與 Pure Virtual Interface

大型的軟體專案在開發前期通常會先將功能較獨立、且共用性高的部分規劃為函式庫。在設計 C/C++ 的函式庫接口時,特別要留意那些要公開給外部使用的 header 檔案。裡面盡可能只包含「要公開的 API 定義」,而將「只有內部才需要」的各種定義或 header 藏起來,以免相依性向外轉嫁到函式庫的使用者。這個動作稱為「Data Hiding」或「Information Hiding」。

舉一個設計不良的例子,假設你要對外公開這個 MyTool 類別,而它的 header 長這樣:

2012年12月18日 星期二

C++ 非靜態成員函式指標語法

C/C++ 語言裡的一個特色是函式 (function) 可視為一級物件 (First-Class Object), 即函數可被當成變數供另一個函數做為參數使用. 對比缺少此特色的語言 (Ex: Java) 來說, 語法上較易表示交付 Callback 或指派 Delegate 等等的應用.

可能是因為 C/C++ 本身的歷史關係, 函數指標的型別宣告方式還蠻艱誨深澀, 基本的全域靜態函式的指標宣告和傳遞可能就能讓許多 Programmer 停下來翻書查語法了. 更別說 C++ 中引入的非靜態成員函式指標語法. 這邊筆記一下網路的參考資料和範例:

2012年11月5日 星期一

Torque3D 引擎提供的實作參考 - 基於 UDP 的網路傳輸層

2011 年的 GDC 年會中, BUNGiE.net 分享了他們在進行 Halo 的遊戲開發時針對一些即時性的網路傳輸議題的處理經驗. 介紹到他們的網路架構時, 較讓我驚訝的是他們採用完全 UDP 的實現. 微軟的 Halo 技術服務頁面也應驗了這一點. 稍一查訪之後發現全 UDP 實作的網路傳輸在遊戲領域中還不算少見, 另一個專門用於遊戲開發的 Raknet 網路函式庫也是採用 UDP 實作 (另提供 TCP wrapper). 在 BUNGiE 分享的投影片內容中, 有提到他們的架構很大程度是延用 1995 年 Tribes 開發團隊同樣是在 GDC 中分享的 "Tribes Networking Model" 中提到的架構. 這篇論文目前還可在網路上找到 (PDF).

2012年10月9日 星期二

使用 Visual Studio Performance Tool 進行 Profiling

要對自己的程式進行優化前, 要先知道實際運行中的時間大都花在哪些函數上. 這時就需要對程式進行 Profiling, 大致如同 MSDN 上這篇廣告文描述的這種過程.

文章裡沒說的是一個小尷尬的現實: Visual Studio 2010 的眾多版本裡, 只有 Premium 和 Ultimate 這兩個版本有內建 Profiler, 免費的 Express 版本自然是沒有. 但付費的 Professional 版本竟然也沒有就不知道作何解釋...

不過微軟倒是有把 Profiling 工具另外打包成一個獨立於 Visual Studio 之外的工具套件, 取名為 Performance Tool, 可以在這裡下載. 透過這個工具套件也一樣可以對程式進行 Profiling, 它最後會產生 Excel 可匯入的 CSV 文件, 也可選擇改為 XML 型式的輸出. 具體使用方式可見這篇文章:

http://codeka.com/blogs/index.php/2009/03/21/got-visual-studio-2008-professional-want

幾點補充:
  1. 原文是針對 Visual Studio 2008 的環境. 但相同內容和步驟在 Visual Studio 2010 中也適用. 只需要將內容中路徑含有 "Microsoft Visual Studio 9.0" 字樣的都改為 "Microsoft Visual Studio 10.0" 即可.
  2. 若是已裝有 Visual Studio 的話, 可直接使用它的 Command Prompt. 就不用自己設定 path.
  3. 建議可直接對 Release 版的程式做 Profiling. Debug 版中由於使用到 Debug CRT 會多做很多事, 出來的 Profiling Report 不儘體積會很龐大, 統計到的函數時間花費也可能失真.

2012年9月24日 星期一

FireBreath 心得 - Mac 篇

2017/10/13 敬告: FireBreath 在非 Windows 平台上所依賴的 NPAPI 已經被各大主流瀏覽器廢棄、禁用。因此 FireBreath 的開發也已暫停 (估計不可能再開)。此處心得只能留作回憶。


上次有發了篇 FireBreah 的心得, 但裡面主要是針對 Windows 上的使用經驗. 最近將同樣的工作移植到了 Mac 平台上, 原本以為熟悉 FireBreath 的大致結構後移植的時間應該會比第一次在 Windows 中開發時來得快. 最後竟花了約預期時間兩倍的時間才大致搞定. 我本身對 Mac 平台並不熟悉, 很多平台細節如視窗事件的處理在原先預期上應該要靠 FireBreath 幫忙處理掉的, 但最後卻發現它也沒有提供很完美的抽象層, 導致最後還是將視窗事件獨立拉出來處理. 所以目前對 Mac 平台也累積了一些 FireBreath 使用經驗, 整理於此供後續參考:

2012年9月6日 星期四

FireBreath 心得

2017/10/13 敬告: FireBreath 在非 Windows 平台上所依賴的 NPAPI 已經被各大主流瀏覽器廢棄、禁用。因此 FireBreath 的開發也已暫停 (估計不可能再開)。此處心得只能留作回憶。

前言


FireBreath 是 2009 年才開始的開源專案, 旨在提供一個瀏覽器插件 (Broswer Plugins) 的抽象層, 把不同瀏覽器插件的實作方式包裝起來, 開放統一後的開發框架給所有的插件開發者. 如此一來要寫一個所有瀏覽器通吃的插件就能簡單一些, 至少可以專注在內容和功能的開發上, 不用擔心與各個瀏覽器接合的問題.

2012年6月26日 星期二

Edge-triggered 和 Level-triggered 用於事件處理時的意義

常在一些介紹網路事件處理的技術文章中看到 Edge-triggeredLevel-triggered 這兩個詞, 我只知道這兩個詞是用來描述硬體中斷的處理模式, 卻不知用在軟體行為上衍生意義為何.

前幾天拜讀了 Dan Kegel 的一篇專文- The C10K problem, 講述伺服器要如何有效地處理網路上的事件通知, 這篇文章的內容對於各式處理 Network I/O 的手法和現有函式庫都講述的蠻詳盡的, 非常有價值. 文內就有解釋這兩個詞用於軟體處理事件行為的意義.


  • Level-triggered 意指事件監看端 (作業系統/Kernel) 在每一次察覺到有新事件時, 都會通知事件接收端 (軟體程式). 
  • Edge-triggered 則指事件監看端 (作業系統/Kernel) 在察覺到有新事件時, 會依照事件接收端 (軟體程式) 的處理狀態 (state) 來決定是否需要通知. 大致流程為: 
    1. 接收端處理狀態初始為 low
    2. 事件發生
    3. 監看端得知接收端狀態為 low, 遂通知接收端並且設定處理狀態為 high
    4. 該狀態會一直保持為 high 直到接收端將所有事件都處理完才會重置回 low, 而期間就算有新事件發生, 監看端也不會發出通知

舉一個生動一點的例子: 國王屬咐太監,如果有大臣來覲見就把它領來書房。這個例子中,國王即為事件接收端、太監則為事件監看端,而大臣的來訪即為事件。如果這個太監是按 Level-triggered 來行事,那麼每來一位大臣他就要領去書房一次。反之若太監以 Edge-triggered 來行事,當領了一位大臣去書房後,他就知道國王是「已經知道有大臣來訪」的狀態 (處理狀態為 high),後續再有大臣來,就會直接放行請大臣自己進去、不再通知國王。直到國王再主動跟太監說「我都謁見完了」(處理狀態重置為 low),之後太監再看到有大臣來訪才會再行通知。

如果要使用 Linux 平台上的 epoll()、或 BSD/MacOS 平台上的 kqueue() 來實作 Async I/O 時,這兩個詞的意義務必要先搞懂的。