伺服器應用面臨雙重挑戰:資料完整性需同步,高併發需減少爭用。單一全域臨界區雖簡單但會過度序列化無關資料的存取;為每個資料項嵌入臨界區則消耗驚人核心資源 (百萬項 = 24MB + 百萬事件物件)。
核心概念:固定大小臨界區陣列 + 雜湊分發。資料項位址雜湊後對應到固定陣列槽位,同一資料項永遠鎖定同一臨界區,不同項目大概率落入不同槽位實現並行。
class CritSecTable {
CritSec m_table[256]; // 固定 256 槽位
unsigned char Hash(void* p) {
// 位址位元組 XOR 折疊,極簡高效
// 32/64 位元平台均優化為少數組合指令
}
public:
void Acquire(void* p) { m_table[Hash(p)].Acquire(); }
void Release(void* p) { m_table[Hash(p)].Release(); }
};
class DBEntry {
static bool g_bUseSingleCritSec;
static CritSec g_singleCritSec;
static CritSecTable g_critSecTable;
void Acquire() {
if (g_bUseSingleCritSec) g_singleCritSec.Acquire();
else g_critSecTable.Acquire(this); // this 指針作為雜湊鍵
}
void Release() { /* 對應釋放 */ }
};
template<class T>
class LockKeeper {
T& m_lock;
public:
LockKeeper(T& t) : m_lock(t) { m_lock.Acquire(); }
~LockKeeper() { m_lock.Release(); }
};
// 使用範例:自動釋放,異常安全
void WorkerThread::DoUpdate(DBEntry& entry, const string& val) {
LockKeeper<DBEntry> lock(entry);
entry.SetValue(val);
SimulateWork(100);
} // 離開作用域自動 Release
圖一 單 CPU:單一臨界區隨執行緒數線性惡化,臨界區表近乎常數
圖二 四 CPU:臨界區表 1→4 執行緒時間暴跌 70%+,展現線性擴展
文中提供完整可復用組件:Exception、Timer、CritSec、LockKeeper、Thread 基礎類別,構建出乾淨、異常安全、跨平台可移植的多執行緒框架。完整測試程式 ConcurrencyDemo 含 CSV 輸出便於 Excel 圖表分析。