某計算模組面臨高頻「計算訊息」衝擊:若逐一處理,CPU 過載;若設固定時間間隔忽略,間隔長漏算、間隔短無效。傳統定時器方案因無法預知最佳間隔而失效。
設計 CFepMergeMessage 工具類:
PostMessage 一個處理訊息 (WM_PROCESS_MESSAGE)。利用 Windows 訊息隊列天然的串行化與延遲特性,完美解決突發高頻事件的合併處理。
#pragma once
#include <afx.h>
class MERGE_MES_HEADER : public CObject {
DECLARE_DYNAMIC(MERGE_MES_HEADER)
public:
typedef void (*MergeMesCallBack)(const MERGE_MES_HEADER* lpMergMes);
MergeMesCallBack pfnCallBack; // 真實處理回調
virtual MERGE_MES_HEADER* Clone() const = 0; // 參數深拷貝
virtual BOOL IsSameMes(const MERGE_MES_HEADER* pMes) const = 0; // 同一性判斷
};
class CFepMergeMessage : public CDialog {
public:
CFepMergeMessage();
virtual ~CFepMergeMessage();
static BOOL Excute(const MERGE_MES_HEADER* pParam); // 靜態入口
protected:
BOOL Create(); // 建立隱藏對話框
afx_msg LRESULT OnMergeMessage(WPARAM, LPARAM); // 合併訊息處理
afx_msg LRESULT OnProcessMessage(WPARAM, LPARAM); // 批次處理訊息
DECLARE_MESSAGE_MAP()
CArray<MERGE_MES_HEADER*, MERGE_MES_HEADER*> m_rgMessage; // 參數隊列
BOOL m_bMessagePosted; // 是否已 Post 處理訊息
};
#include "StdAfx.h"
#include "FepMergeMessage.h"
#include "../Include/FepPtr.h"
#define WM_MERGE_MESSAGE WM_USER + 100
#define WM_PROCESS_MESSAGE WM_USER + 200
IMPLEMENT_DYNAMIC(MERGE_MES_HEADER, CObject)
static CFepPtr<CFepMergeMessage> pDlgMergeMessage(NULL);
CFepMergeMessage::CFepMergeMessage() : m_bMessagePosted(FALSE) { Create(); }
CFepMergeMessage::~CFepMergeMessage() {
for (int i = 0; i < m_rgMessage.GetSize(); ++i) delete m_rgMessage.GetAt(i);
m_rgMessage.RemoveAll();
}
BEGIN_MESSAGE_MAP(CFepMergeMessage, CDialog)
ON_MESSAGE(WM_MERGE_MESSAGE, OnMergeMessage)
ON_MESSAGE(WM_PROCESS_MESSAGE, OnProcessMessage)
END_MESSAGE_MAP()
BOOL CFepMergeMessage::Create() {
if (GetSafeHwnd()) return TRUE;
DWORD dwDlgTempl[100] = {0};
DLGTEMPLATE* pDlgTmp = (DLGTEMPLATE*)dwDlgTempl;
pDlgTmp->style = WS_POPUP | DS_CONTROL;
pDlgTmp->cx = 1; pDlgTmp->cy = 1;
return CDialog::CreateIndirect(pDlgTmp);
}
BOOL CFepMergeMessage::Excute(const MERGE_MES_HEADER* pParam) {
if (!pDlgMergeMessage.m_pPtr) pDlgMergeMessage.m_pPtr = new CFepMergeMessage;
if (!pDlgMergeMessage->GetSafeHwnd()) return FALSE;
pDlgMergeMessage->SendMessage(WM_MERGE_MESSAGE, (WPARAM)pParam, 0);
return TRUE;
}
LRESULT CFepMergeMessage::OnMergeMessage(WPARAM wParam, LPARAM) {
const MERGE_MES_HEADER* pNewMes = (const MERGE_MES_HEADER*)wParam;
// 合併邏輯:同類型且 IsSameMes 為真則替換
for (int i = 0; i < m_rgMessage.GetSize(); ++i) {
MERGE_MES_HEADER* pMes = m_rgMessage.GetAt(i);
if (pNewMes->IsKindOf(pMes->GetRuntimeClass()) && pNewMes->IsSameMes(pMes)) {
delete pMes;
m_rgMessage.RemoveAt(i);
--i;
}
}
m_rgMessage.Add(pNewMes->Clone()); // 儲存副本
if (!m_bMessagePosted) {
PostMessage(WM_PROCESS_MESSAGE, 0, 0); // 排程批次處理
m_bMessagePosted = TRUE;
}
return 0;
}
LRESULT CFepMergeMessage::OnProcessMessage(WPARAM, LPARAM) {
while (m_rgMessage.GetSize() > 0) {
MERGE_MES_HEADER* pHeader = m_rgMessage.GetAt(0);
pHeader->pfnCallBack(pHeader); // 執行真實回調
delete pHeader;
m_rgMessage.RemoveAt(0);
}
m_bMessagePosted = FALSE;
return 0;
}
每個使用此工具的模組必須繼承 MERGE_MES_HEADER 並實作三大核心:
| 成員 | 類型 | 職責 |
|---|---|---|
pfnCallBack | 函數指標 | 真正的業務處理邏輯 |
Clone() | 純虛函數 | 深拷貝自身,供隊列儲存副本 |
IsSameMes() | 純虛函數 | 判斷新訊息是否與現有訊息「同一」 (可合併) |
// 1. 定義具體參數類別
class CCalcMes : public MERGE_MES_HEADER {
public:
int nParam1, nParam2;
CCalcMes(int p1, int p2) : nParam1(p1), nParam2(p2) {
pfnCallBack = &CCalcMes::DoCalc; // 靜態回調
}
virtual MERGE_MES_HEADER* Clone() const { return new CCalcMes(*this); }
virtual BOOL IsSameMes(const MERGE_MES_HEADER* pMes) const {
const CCalcMes* p = static_cast<const CCalcMes*>(pMes);
return p && nParam1 == p->nParam1; // 同參數1視為同一訊息
}
static void DoCalc(const MERGE_MES_HEADER* pMes) {
const CCalcMes* p = static_cast<const CCalcMes*>(pMes);
// 真實計算邏輯...
}
};
// 2. 觸發合併處理 (任意執行緒均可呼叫)
void OnDataArrive(int p1, int p2) {
CCalcMes* pMes = new CCalcMes(p1, p2);
CFepMergeMessage::Excute(pMes); // 靜態方法,線程安全
}
SendMessage 同步投遞合併訊息,PostMessage 異步排程處理,不阻塞生產者。Clone/Delete 配對管理記憶體。此模式適用於所有「高頻觸發、結果冪等、需批次處理」的場景:即時繪圖刷新、日誌批次寫入、網路封包合併發送、感應器資料聚合等。