ProudNet 實用程式

使用收藏

STL、ATL等也已經提供收藏類(std.map, std.vector, CFastArray, CAtlArray, CAtlMap等)。 但是ProudNet在STL和ATL都難以使用的情況下,或在要求高速性能的情況下提供有效的類

快速內存管理器

ProudNet內置高性能內存管理器,開發者可以利用高性能內存管理器加速應用程序的加工性能。

ProudNet支持的存儲管理器大致如下。

- Lookaside allocator

Lookaside allocator應用了通常的memory pool技術。 如果您必須經常分配/ 釋放相同大小的內存, 推薦使用 Lookaside allocator

主要機制如下。

  • 分配新的存儲塊時,分配新的系統內存。

  • 當解鎖存儲塊時,解鎖的塊將返回至lookaside allocator

  • 重新分配存儲塊時,返還給lookaside allocator的存儲塊將被再利用。

這個過程以非常快的速度運行。 比OS環境下的內存分配速度要快得多。

但也存在缺點。

  • Lookaside allocator總是隻能分配大小相同的內存。

  • 分配給 Lookaside allocator 的內存塊必須在 Lookaside allocator 被破壞之前全部釋放。

使用Lookaside allocator的方法如下。

  • 首先使用 Proud.CLookasideAllocator.New 方法創建對象。 創建全局對象也可以。

  • 將存儲塊分配給 Proud.CLookasideAllocator.Alloc 方法。

  • 解除設置爲 Proud.CLookasideAllocator.Free。 Realloc不存在。

  • 解除所有存儲塊後,破壞 Proud.CLookasideAllocator 對象。

- Fast Heap

ProudNet的Fast heap雖然比Lookaside allocator稍微慢一些,但是比OS環境下的存儲器分配/解除速度更快,可以分配/解除各種大小的存儲器塊。

ProudNet 的 Fastheap 的實現類是 Proud.CFastHeapProud.CFastHeap 還可以在所有存儲塊被破壞後移除 Proud.CFastHeap 對象。

Fast heap的使用方法如下。

  • 首先以Proud.CFastHeap.New方法生成Fast heap對象。 創建全局對象也可以。

  • Proud.CFastHeap.Alloc 方法分配內存塊 。

  • 解除爲Proud.CFastHeap.Free。 可用CFastHeap.Realloc重新分配內存塊。

  • 解除所有存儲塊後,破壞 Proud.CFastHeap 對象。

指定為 C++ 類別的預設分配器

在C++類中容易接受Fast heapLookaside allocator的加速的方法是覆蓋C++的operator new, delete方法。

這樣,在創建和破壞C++類作爲new、delete操作符時,將使用Fast heapLookaside allocator代替系統的內存heap。

在以下示例中,當將類實例化到 operator newdelete 時,高性能內存管理器將允許您分配/ 釋放內存。 它們各有優缺點,請適當選擇使用。

智能指示器

ProudNet擁有智能指針Proud.RefCount類。

智能指針是指,只要存在參照生成客體的變數,就能起到保障該客體的存在本身的作用。 而且,只有當參照該客體的變數不再存在時,該客體纔會被破壞。

它還可以解決由於開發人員創建的錯誤(dangling)而引用已被銷毀的物件的問題或未銷毀物件的問題(leak)。

智能指針變量每次複製時客體參考計數增加1,下圖中Object Instance一直存在到參考計數爲0。

有時候想在多處參照客體的智能指示器的狀態下強制破壞客體。

例如,如果智能指示器參考擁有打開文件手柄的對象,則有時需要立即破壞擁有文件手柄的對象。

但如果智能指示器到處參照客體,就無法知道客體被破壞的時間,因此可能會遇到難關。 在這種情況下,可以使用Dispose Pattern明確執行多處參考對象的破壞。

- Dispose Pattern

Dispose Pattern是一種程序模式,即使不知道一個以上智能指示器所參照的對象被破壞的時間,也能獲得明確破壞客體的效果。

如果要將Dispose Pattern運用到智能類客體上,作爲客體的成員變數,具有"自我狀態",這意味着客體是否已經被破壞,無法使用。 如果自己的狀態是"已經破壞的狀態",那麼在參考客體時就會發生錯誤,否則就要讓其正常執行。

下面是運用Dispose Pattern的例子。

Dispose Pattern 是 在Java或C#等智能指示器Garbage Collector的程序設計語言中也有涉及。

線程實用程式

ProudNet提供了一些線程實用類。

字符串類

ProudNet使字符串類Proud.String, Proud.StringA使字符串像ATL或STL的字符串類一樣可以簡便地處理。

使用 .Net Framework 的程序具有名爲 System.string 的符號。 因此.Net Framework混用時,可能需要註明System或Proud中的一個命名空間。

舉例如下。

Proud::String a;  // 空字符串
a = L"123";         // 爲字符串添加值 。
puts(a);            // a本身直接提供字符串緩衝器。
a += L"abc";        // 向字符串添加另一個字符串
if(L"123abc" == a)  // 如何比較字符串中的內容
{
    a.Replace(L"123", "def");   // 字符串內容替換
}

- 創建字符串功能(format)

Proud.StringT 提供了創建字符串的功能, 如 sprintf()

Proud::String a;
a.Format(L"%d %d %s", 1, 2, L"hahaha");
// 現在a="12 hahaha"。

- 字符串處理性能

Copy-on-write

// Proud.StringT 的 copy-on-write 功能只有在需要字符串時才顯示副本。 
// 在此之前,我們會互相共享字符串數據 。
 
Proud::String a = L"abc"; // a 擁有字符串'abc'
Proud::String b = a; // b共享與a相同的字符串數據
Proud::String c = b; // 現在a、b、c都共享相同的字符串數據。
c = L"bcd"; // a、b仍然共享字符串數據"abc",但c不再共享,單獨擁有"bcd"
b = c; // b放棄與a共享"abc",共享c擁有的"bcd"

字符串長度測量

Proud.StringT.GetLength在調用後立即返回預先測量的字符串長度。 即與strlen()不同。

Proud.StringT 和 int 和 float 一樣, 不使用 thread safe 。 因此,同時從多個執行緒存取同一個字串物件是不安全的(除非所有執行緒都只是讀取)。

這一點與ATL或STL的字符串類別相同。

Timer Queue

Timer Queue是在線程池中執行tick event的模塊,在Windows XP,2000年以後版本的操作系統上提供名爲Windows Timer Queue的API。

每隔一段時間運行用戶指定的函數, 該函數在線程池中的一個線程中運行。 如果所有線程正在運行(running state) 函數的執行將保留到線程中出現完成歷史任務線程爲止。

Timer Queue中呼叫的用戶函數是從線程池中的線程中選擇一個,如果之前正在運行的用戶函數處於未運行狀態,也有無事可做的線程(idle state),則選擇該線程並執行用戶函數。

假設有以下工作清單。

黑箭頭爲0.1s,A、B、C、D、E是每0.1s應做的工作項目。 A、D在0.1秒內結束,B在0.1秒內結束,C、E在0.1秒內無法結束。

如果是服務器主環方法,則這些操作項目如下圖所示。 由於在一個線程中運行所有任務項目,D、E不能按時啓動。

然而,在Timer Queue方法中,動員了另一個線程來運行D,並且E及時運行在先前完成C的線程中。

及時啓動必要任務,必要時進一步調動線程。

Timer Queue主要在服務器程序中使用,因爲用戶函數可能同時在兩個或多個線程中運行。

實現並列性,但需承受並列性所具有的危險性,使用前請判斷該功能是否必要。

如果錯誤地使用 Timer Queue 服務器過程的線程會爆炸性地增加,對性能產生不利影響。 如果沒有必須使用 Timer Queue的原因, 請在 Proud.CTimerThread服務器上使用計時器環路, RMI, 事件處理

- 如何使用計時器隊列

您需要存取 Proud.CTimerQueue 類別。 這個類別是一個singleton。

如果將調用函數和調用週期設置爲 Proud::NewTimerParam 結構,並將其作爲參數添加到 Proud.CTimerQueue.NewTimer 中,則會獲得 Proud.CTimerQueueTimer 對象。 然後,在破壞 Proud.CTimerQueueTimer 對象之前,指定的用戶函數每隔一段時間運行一次。

留下日誌

在開發網絡遊戲的過程中,必然需要留下各種執行記錄(日誌)的功能。 ProudNet爲此提供日誌留存功能。

ProudNet的登錄功能以非同步方式運行,因此,在調用要留下登錄的方法後,方法立即返回。 此外,將單獨線程的實際日誌記錄在文件或數據庫中。

- 日誌記錄到文件

Proud::CLogWriter 類是允許將日誌寫入文件的類 。

- 日誌記錄到數據庫

Proud::CDbLogWriter 類是允許將日誌寫入DB 的類 。

爲此,您必須運行 Sample/DbmsSchema 文件夾中的 LogTable.sql,以預先生成 LogTable 。 DBMS的建立參考樣品數據庫建立的程序。

延遲測量功能

ProudNet以StopWatch的形式提供延遲測量功能。

如果是可用的版本,則必須使用比現有延遲測量函數更準確的該功能,而不是服務器的GetLastPingGetRecentPing

(1) 開始延遲測量

調用 StartRoundTripLatencyTest 將開始要測量延遲的目標和 relay 。

(2) 延遲測量結束

如果您想在先前指定的測試Duration之前停止測試, 請調用StopRoundTripLatencyTest函數 。 如果直到testDuration結束爲止不呼叫StopRoundTripLatencyTest,則將自動停止測量。

(3) 獲取延遲測量值

PIDL 編譯器插件

這是 Visual Studio 的附加元件,可協助您輕鬆設定 PIDL (ProudNet IDL) 檔案的自訂建置。

- 安裝

1. 運行 <安裝路徑>\ProudNet\util\PIDL-addon.vsix

2. 選擇要安裝附加元件的 Visual Studio 並繼續安裝。

3. 安裝成功完成後,會顯示如下圖所示。

- 刪除

可以透過ToolsExtensions and Updates選單將其刪除。

對於 Visual Studio 2010, ToolsExtension Manager

- 新增PIDL檔案視窗

調用 PIDL 新增視窗。 選擇選擇項目右鍵Add new PIDL file

  1. 輸入 PIDL 文件名 。

  2. 顯示添加 PIDL 文件的路徑 。

  3. 添加外部 PIDL 文件 。

  4. 創建新的 PIDL 文件 。

  5. 關閉 PIDL 附加窗口 。

- 添加 PIDL 文件

  1. 輸入要添加的 PIDL 文件名

  2. 點擊 New PIDL

如上圖所示,添加了PIDL文件,該文件默認設置Custom Build。 與默認設置不同時,可通過文件屬性更改功能進行更改。

- PIDL 文件屬性窗口

調用 PIDL 屬性窗口 。

選擇 PIDL 文件右鍵點擊Properties 選擇

  1. 檢查/ 更改 PIDL 文件中的 Custom Build Tool 設置 。 PIDL Compiler Location: 設置 PIDL 編譯器位置 。 PIDL Compiler Location is Relative: 輸入路徑的絕對/相對與否值。 Output Directory (All Languages): 設置輸出路徑 。 Output Directory is Relative (All Languages): 輸入路徑的絕對/相對與否值。

  1. 各語言設置窗口:可按各C++、C#、Java、Unreal Script語言生成。

  2. 特定於語言的設定視窗: Generate Code: C++ 默認 Yes, 其餘語言是 False (可根據需要配置) C++ Implementation File Extension: 僅限C++。

Last updated