ms精度定时器
MsTimer.h
#ifndef __MS_TIMER #define __MS_TIMER/* C++標(biāo)準(zhǔn)庫頭文件 */ #include <list> #include <map> #include <windows.h>/* 定時器的定時精度范圍 */ #define OSSYSTIME_MININTERVAL (1) #define OSSYSTIME_MAXINTERVAL (65535) #define IMOS_UNUSED_ARG(x) ((VOID) x)/* 定時器嘗試最大次數(shù) */ #define OSTOTAL_TIMERID_TRYNUM (1000)/* 定時器Flag標(biāo)記 */ #define OSTIME_KILL_SYNCHRONOUS 0x1 #define OSTIME_PERIODIC 0x2 #define OSTIME_ADJUST_PERIODIC 0x4 //用戶在回調(diào)函數(shù)中能夠動態(tài)修改定時器下次觸發(fā)的時間間隔/* 定義定時器函數(shù)的錯誤碼 */ #define OSTIME_NO_ERR 0 #define OSTIME_ERR 1#define OSTIME_PREC 1000 //當(dāng)前定時器的精度細分 #define OSTIME_MAX_DELAY_CYC 10 //當(dāng)定時器延時超過10個周期時,需要進行定時器時間復(fù)位 #define OSTIME_33MS_ADJUST_TIME_VAL 40 //對周期為33ms的進行周期修改值,用于規(guī)避IPC 30幀每秒時幀率不足問題/** * 定時器回調(diào)函數(shù)類型定義 * @param [IN] ulTimerID 執(zhí)行回調(diào)函數(shù)的定時器ID號 * @param [IN] ulmsg 參數(shù)未使用 * @param [IN] ulUser 定時器回調(diào)函數(shù)攜帶的參數(shù)信息,該參數(shù)由OstimeSetEvent函數(shù)的ulUser參數(shù)傳入 * @param [IN] ul1 參數(shù)未使用 * @param [IN] ul2 參數(shù)未使用 * @return 無 */ typedef VOID (* LPOSTIMECALLBACK)(IN unsigned int ulTimerID, IN unsigned int ulmsg, IN ULONG ulUser, IN unsigned int ul1, IN unsigned int ul2);/* 定時器中的list隊列中的控制塊結(jié)構(gòu) */ typedef struct tagOS_TIMERENTRY {unsigned int ulDelay; /* 等待的時間 */unsigned int ulResol;LPOSTIMECALLBACK lpFunc; /* 該定時器的回調(diào)函數(shù) */ULONG ulUser;unsigned int ulFlags;unsigned int ulTimerID;LONGLONG llTriggerTime;LPVOID arg;struct tagOS_TIMERENTRY* pstNextOsTimerEntry; } STOSTIMERENTRY, *PSTOSTIMERENTRY;class MsTimer { public:MsTimer(void);~MsTimer(void); public:unsigned int OSTIME_TimeStart(VOID);VOID OSTIME_TimeStop(VOID);unsigned int OstimeSetEvent(IN unsigned int ulDelay, IN unsigned int ulResol, IN LPOSTIMECALLBACK lpFunc, IN ULONG ulUser, IN unsigned int ulFlags);private:static LONGLONG OsGetTickCount64(LPVOID arg);static DWORD CALLBACK OSTIME_SysTimeThread(IN LPVOID arg);static unsigned int OSTIME_SysTimeCallback(IN LPVOID arg);static VOID OSTIME_TriggerCallBack(IN PSTOSTIMERENTRY lpTimer);unsigned int OSTIME_SetEventInternal(IN unsigned int ulDelay, IN unsigned int ulResol, IN LPOSTIMECALLBACK lpFunc, IN ULONG ulUser, IN unsigned int ulFlags);unsigned int OsGenTimerID(VOID);VOID OsReleaseTimerID(IN unsigned int ulTimerID);unsigned int OstimeKillEvent(IN unsigned int ulTimerID);private:/* 定時器變量 */HANDLE m_hOsTimeMMTimer ; /*定時器線程句柄*/PSTOSTIMERENTRY m_pstOsTimersList ; /*定時器控制隊列*/PSTOSTIMERENTRY m_pstTimersArray ; /*用于保存回調(diào)函數(shù)的數(shù)組*/int m_lSizeLpTimers; /*定時器回調(diào)函數(shù)數(shù)組的內(nèi)存長度*/HANDLE m_hOsTimeKillEvent ; /*定時器同步退出標(biāo)記*/HANDLE m_hOsTimeWakeEvent ; /*定時器線程觸發(fā)事件*/BOOL m_bOsTimeToDie; /*定時器線程退出標(biāo)記*/HANDLE m_hOSTimeHeap; /*用于定時器模塊內(nèi)存分配堆*//* 跟TimerID生成有關(guān)的變量 */std::map<unsigned int, unsigned int> m_mapOsTimerID; /*定時器ID維護隊列*/CRITICAL_SECTION m_OSTimerID_cs; /*定時器ID維護關(guān)鍵段*/CRITICAL_SECTION m_GetSystemTime_cs; /*定時器相對時間獲取關(guān)鍵段*/CRITICAL_SECTION m_OsTime_cs; /*定時器控制塊維護關(guān)鍵段*/LARGE_INTEGER m_lgCurTime; /*系統(tǒng)啟動后的相對時間*/unsigned int m_ulCurTimerID ; /*定一個全局的定時器ID號 */unsigned long m_ulTimerID; //定時器ID}; #endifMsTimer.cpp
#include "MsTimer.h"#pragma comment(lib,"winmm.lib")MsTimer::MsTimer(void) {m_hOsTimeMMTimer = NULL;m_pstOsTimersList = NULL;m_pstTimersArray = NULL;m_lSizeLpTimers = 0;m_hOsTimeKillEvent = NULL;m_hOsTimeWakeEvent = NULL;m_bOsTimeToDie = TRUE;m_hOSTimeHeap = NULL;m_ulCurTimerID = 0;m_ulTimerID = -1; }MsTimer::~MsTimer(void) { }/* 定時器庫對外函數(shù)接口 *//** * 定時器內(nèi)部線程運行啟動函數(shù),在啟動定時前必須調(diào)用的函數(shù),必須同OSTIME_TimeStop配套使用 * @param [IN] 無 * @return OSTIME_NO_ERR 返回成功 * OSTIME_ERR 返回失敗 */unsigned int MsTimer::OSTIME_TimeStart( VOID ) {/* 判斷當(dāng)前是否已經(jīng)啟動了定時器線程,沒有啟動則啟動定時器線程 */if ((HANDLE) NULL == m_hOsTimeMMTimer){m_pstOsTimersList = NULL;m_hOsTimeWakeEvent = CreateEventW(NULL, FALSE, FALSE, NULL);if ((HANDLE) NULL == m_hOsTimeWakeEvent){/* dsp_log(MOD_OSTIME, DSP_LOG_ERROR,"[ERROR] OSTIME_TimeStart: Failed to create an Time wake Event for pstTimerEntry running! ErrorCode:%u\n",GetLastError());*/return OSTIME_ERR;}m_bOsTimeToDie = FALSE;/* 創(chuàng)建一個堆供定時器模塊使用 */m_hOSTimeHeap = HeapCreate(0, 0, 0);if ((HANDLE) NULL == m_hOSTimeHeap){/* dsp_log(MOD_OSTIME, DSP_LOG_ERROR,"[ERROR] OSTIME_TimeStart: Failed to create an Time Heap for timer running need! ErrorCode:%u\n",GetLastError());*/CloseHandle(m_hOsTimeWakeEvent);m_hOsTimeWakeEvent = (HANDLE) NULL;return OSTIME_ERR;}m_hOsTimeMMTimer = CreateThread(NULL, 0, OSTIME_SysTimeThread, this, 0, NULL);if ((HANDLE) NULL == m_hOsTimeMMTimer){/* dsp_log(MOD_OSTIME, DSP_LOG_ERROR,"[ERROR] OSTIME_TimeStart: Failed to create an Time thread for pstTimerEntry running! ErrorCode:%u\n",GetLastError());*/CloseHandle(m_hOsTimeWakeEvent);m_hOsTimeWakeEvent = (HANDLE) NULL;HeapDestroy(m_hOSTimeHeap);m_hOSTimeHeap = (HANDLE) NULL;return OSTIME_ERR;}InitializeCriticalSection(&m_OsTime_cs);InitializeCriticalSection(&m_OSTimerID_cs);InitializeCriticalSection(&m_GetSystemTime_cs);/* 對返回錯誤不進行特別處理,只是定時器線程的優(yōu)先級會降低一點 */if (0 == SetThreadPriority(m_hOsTimeMMTimer, THREAD_PRIORITY_TIME_CRITICAL)){/* dsp_log(MOD_OSTIME, DSP_LOG_ERROR,"[ERROR] OSTIME_TimeStart: Failed to set pstTimerEntry thread Priorty!ErrorCode:%u!\n",GetLastError());*/}/*dsp_log(MOD_OSTIME, DSP_LOG_TRACE,"[TRACE] OSTIME_TimeStart: Have create an pstTimerEntry thread for pstTimerEntry running! The thread ID %u, The handle of timer heap is %u\n",gshOsTimeMMTimer, gshOSTimeHeap);*/m_lgCurTime.QuadPart = 0;}return OSTIME_NO_ERR;}/** * 定時器內(nèi)部線程關(guān)閉函數(shù),在退出時必須調(diào)用的函數(shù),必須同OSTIME_TimeStart配套使用 * @param [IN] 無 * @return 無 */ VOID MsTimer::OSTIME_TimeStop(VOID) {OstimeKillEvent(m_ulTimerID);if ((HANDLE) NULL != m_hOsTimeMMTimer){/* dsp_log(MOD_OSTIME, DSP_LOG_TRACE,"[TRACE] OSTIME_TimeStop: Have stop an pstTimerEntry thread for pstTimerEntry running! The thread ID %u\n",gshOsTimeMMTimer);*/m_bOsTimeToDie = TRUE;if (0 == SetEvent(m_hOsTimeWakeEvent)){/* dsp_log(MOD_OSTIME, DSP_LOG_ERROR,"[ERROR] OSTIME_TimeStop: Failed to set gshOsTimeWakeEvent event to stop timer running thread! ErrorCode:%u\n",GetLastError());*/}/* 等待定時器線程退出 */DWORD dwRetVal = WaitForSingleObject(m_hOsTimeMMTimer, INFINITE);if ((WAIT_TIMEOUT != dwRetVal) && (WAIT_OBJECT_0 != dwRetVal)){/* 定時器線程運行出現(xiàn)了異常,現(xiàn)在需要進行退出 *//* dsp_log(MOD_OSTIME, DSP_LOG_ERROR,"[ERROR] OSTIME_TimeStop: The thread ID %u will exit with Calling WaitForSigleObject function! ErrorCode:%u\n",gshOsTimeMMTimer, GetLastError());*/}CloseHandle(m_hOsTimeMMTimer);m_hOsTimeMMTimer = (HANDLE) NULL;CloseHandle(m_hOsTimeWakeEvent);m_hOsTimeWakeEvent = (HANDLE) NULL;if ((HANDLE) NULL != m_hOsTimeKillEvent){CloseHandle(m_hOsTimeKillEvent);m_hOsTimeKillEvent = (HANDLE) NULL;}/* 增加錯誤判斷,查看定時器調(diào)用函數(shù)外部是否調(diào)用匹配 */if ((NULL != m_pstOsTimersList) || (0 != m_mapOsTimerID.size())){/* dsp_log(MOD_OSTIME, DSP_LOG_ERROR,"[ERROR] OSTIME_TimeStop: the OstimeSetEvent function is mistach with the OstimeKillEvent function call! the size of gsmapOsTimerID is %u\n",gsmapOsTimerID.size());*/}m_pstOsTimersList = NULL;DeleteCriticalSection(&m_OsTime_cs);DeleteCriticalSection(&m_OSTimerID_cs);DeleteCriticalSection(&m_GetSystemTime_cs);HeapDestroy(m_hOSTimeHeap);m_hOSTimeHeap = (HANDLE) NULL;/*將定時器的ID號也進行復(fù)位*/m_ulCurTimerID = 0;m_lgCurTime.QuadPart = 0;}} /** * 啟動一個定時器 * @param [IN] ulDelay 定時器的周期,單位ms,范圍必須為[1、65535]. * @param [IN] ulResol 為兼容windows操作系統(tǒng)的函數(shù),參數(shù)未啟用。 * @param [IN] lpFunc 回調(diào)函數(shù),必須為LPOSTIMECALLBACK的函數(shù)指針 * @param [IN] ulUser 傳遞給回調(diào)函數(shù)的參數(shù)。 * @param [IN] ulFlags 標(biāo)識當(dāng)前定時器的類型,現(xiàn)在只支持兩種標(biāo)記:OSTIME_KILL_SYNCHRONOUS 當(dāng)前為同步定時器,OstimeKillEvent返回時必須保證不再進行回調(diào)函數(shù)調(diào)用OSTIME_PERIODIC 是否需要周期調(diào)用回調(diào)函數(shù),不設(shè)置則屬于一次性定時器 * @return 定時器ID號,如果失敗,則返回的定時器ID號為0,成功返回非0值 */unsigned int MsTimer::OstimeSetEvent( IN unsigned int ulDelay, IN unsigned int ulResol, IN LPOSTIMECALLBACK lpFunc, IN ULONG ulUser, IN unsigned int ulFlags ) {unsigned int ulFps = (1000/ulDelay);unsigned int msInterval = (1000 * OSTIME_PREC)/ulFps;/* 對33ms為周期的定時器進行微調(diào),規(guī)避IPC 30幀每秒時幀率不足問題 */if (ulDelay == 33){msInterval += OSTIME_33MS_ADJUST_TIME_VAL;}m_ulTimerID = OSTIME_SetEventInternal(msInterval, ulResol, lpFunc, ulUser, ulFlags);return m_ulTimerID;}/** * 停止一個定時器 * @param [IN] ulTimerID 定時器ID號。 * @return OSTIME_ERR 表示刪除定時器失敗 * OSTIME_NO_ERR 表示刪除定時器成功 */ unsigned int MsTimer::OstimeKillEvent( IN unsigned int ulTimerID ) {PSTOSTIMERENTRY pstSelfTimerEntry = NULL;PSTOSTIMERENTRY *ppstTimerEntry = NULL;EnterCriticalSection(&m_OsTime_cs);/* 遍歷列表尋找定時器對象 */for (ppstTimerEntry = &m_pstOsTimersList; *ppstTimerEntry; ppstTimerEntry = &(*ppstTimerEntry)->pstNextOsTimerEntry){if (ulTimerID == (*ppstTimerEntry)->ulTimerID){pstSelfTimerEntry = *ppstTimerEntry;*ppstTimerEntry = (*ppstTimerEntry)->pstNextOsTimerEntry;break;}}LeaveCriticalSection(&m_OsTime_cs);if (NULL == pstSelfTimerEntry){/* 表示關(guān)閉定時器失敗 *//* dsp_log(MOD_OSTIME, DSP_LOG_ERROR,"[ERROR] OstimeKillEvent: Cann't find OsTimer[TimerID: %u] in gspstOsTimersList\n",ulTimerID);*/return OSTIME_ERR;}/* 同步退出需要等待回調(diào)函數(shù)調(diào)用完成 */if (0 != (pstSelfTimerEntry->ulFlags & OSTIME_KILL_SYNCHRONOUS)){DWORD dwRetVal = WaitForSingleObject(m_hOsTimeKillEvent, INFINITE);if ((WAIT_TIMEOUT != dwRetVal) && (WAIT_OBJECT_0 != dwRetVal)){/* 定時器線程運行出現(xiàn)了異常,現(xiàn)在需要進行退出 *//* dsp_log(MOD_OSTIME, DSP_LOG_ERROR,"[ERROR] OstimeKillEvent: The pstTimerEntry ID %u will exit with Calling WaitForSigleObject function! ErrorCode:%u\n",ulTimerID, GetLastError());*/}}/* 需要歸還分配的定時器ID號 */OsReleaseTimerID(pstSelfTimerEntry->ulTimerID);HeapFree(m_hOSTimeHeap, 0, pstSelfTimerEntry);pstSelfTimerEntry = NULL;return OSTIME_NO_ERR; }/** * 包裝windows定時器支持獲得64位時間信息,注:該函數(shù)需要外部保證不進行多線程調(diào)用 * @param [IN] 無 * @return 當(dāng)前的系統(tǒng)時間,返回的為相對時間,精度為ms, */ LONGLONG MsTimer::OsGetTickCount64( LPVOID arg ) {DWORD dwCurTime = timeGetTime();MsTimer* pUser =(MsTimer*) arg;/* 判斷時間是否產(chǎn)生溢出 */if (dwCurTime <pUser->m_lgCurTime.LowPart){pUser->m_lgCurTime.HighPart++;}pUser->m_lgCurTime.LowPart = dwCurTime;return pUser->m_lgCurTime.QuadPart*OSTIME_PREC;} /** * 線程啟動回調(diào)函數(shù),該函數(shù)有定時器線程調(diào)用 * @param [IN] arg 沒有使用 * @return 返回值為window線程啟動函數(shù)固有。 */ DWORD CALLBACK MsTimer::OSTIME_SysTimeThread( IN LPVOID arg ) {DWORD dwSleepTime = 0; /* 用于記錄當(dāng)前定時器隊列中最小的等待時間 */DWORD dwRetVal = 0;IMOS_UNUSED_ARG(arg);MsTimer* pUser =(MsTimer*) arg;while (FALSE == pUser->m_bOsTimeToDie){dwSleepTime = OSTIME_SysTimeCallback(arg);if (0 == dwSleepTime){continue;}dwRetVal = WaitForSingleObject(pUser->m_hOsTimeWakeEvent, dwSleepTime);if ((WAIT_TIMEOUT != dwRetVal) && (WAIT_OBJECT_0 != dwRetVal)){/* 定時器線程運行出現(xiàn)了異常,現(xiàn)在需要進行退出 *//* dsp_log(MOD_OSTIME, DSP_LOG_ERROR,"[ERROR] OSTIME_SysTimeThread: The thread ID %u will exit with Calling WaitForSigleObject function! ErrorCode:%u\n",gshOsTimeMMTimer, GetLastError());*/break;}}/* 釋放定時器回調(diào)函數(shù)(OSTIME_SysTimeCallback)的緩存數(shù)組內(nèi)存 */if (NULL != pUser->m_pstTimersArray){HeapFree(pUser->m_hOSTimeHeap, 0, pUser->m_pstTimersArray);pUser->m_pstTimersArray = NULL;}/* 在數(shù)組內(nèi)存清空時需要將長度標(biāo)記為進行情況 */pUser->m_lSizeLpTimers = 0;return 0;}/** * 定時器線程的執(zhí)行函數(shù),被上面線程回調(diào)函數(shù)調(diào)用 * @param [IN] 無 * @return 當(dāng)前定時器鏈表需要等待的間隔時間,單位為ms */ unsigned int MsTimer::OSTIME_SysTimeCallback( LPVOID arg ) {MsTimer* pUser =(MsTimer*) arg;PSTOSTIMERENTRY pstTimerEntry = NULL;PSTOSTIMERENTRY *ppstTimerEntry = NULL;PSTOSTIMERENTRY *ppstNextTimerEntry = NULL;int lIndex = 0;LONGLONG llCurTime = 0;DWORD dwDeltaTime = 0;DWORD dwRetTime = INFINITE;DWORD dwAdjustTime = 0;LARGE_INTEGER lgTempTime;lgTempTime.QuadPart = 0;/* 定時器隊列為空,現(xiàn)在直接退出 */if (NULL == pUser->m_pstOsTimersList){return(dwRetTime);}/* 獲得當(dāng)前的系統(tǒng)時間,進行時間校正使用 */EnterCriticalSection(&pUser->m_GetSystemTime_cs);llCurTime = OsGetTickCount64(arg);LeaveCriticalSection(&pUser->m_GetSystemTime_cs);/* 掃描整個列表,計算新的時間戳信息,將需要回調(diào)的對象放置到一個數(shù)組中進行回調(diào) */EnterCriticalSection(&pUser->m_OsTime_cs);for (ppstTimerEntry = &pUser->m_pstOsTimersList; *ppstTimerEntry != NULL; ){pstTimerEntry = *ppstTimerEntry;ppstNextTimerEntry = &pstTimerEntry->pstNextOsTimerEntry;if (llCurTime >= pstTimerEntry->llTriggerTime){if (NULL != pstTimerEntry->lpFunc){if (lIndex == pUser->m_lSizeLpTimers){/* 標(biāo)識當(dāng)前的定時器存放空間已經(jīng)不足,需要進行動態(tài)申請 */if (NULL != pUser->m_pstTimersArray){pUser->m_pstTimersArray = (PSTOSTIMERENTRY) HeapReAlloc(pUser->m_hOSTimeHeap, 0, pUser->m_pstTimersArray, ((DWORD)(++pUser->m_lSizeLpTimers)) * sizeof(STOSTIMERENTRY));if (NULL == pUser->m_pstTimersArray){/*dsp_log(MOD_OSTIME, DSP_LOG_ERROR,"[ERROR] OSTIME_SysTimeCallback: Failed to call HeapReAlloc with %u Bytes\n",(DWORD) gslSizeLpTimers * sizeof(STOSTIMERENTRY));*/lIndex = 0;pUser->m_lSizeLpTimers = 0;break;}}else{pUser->m_pstTimersArray = (PSTOSTIMERENTRY) HeapAlloc(pUser->m_hOSTimeHeap, 0, ((DWORD)(++pUser->m_lSizeLpTimers)) * sizeof(STOSTIMERENTRY));if (NULL == pUser->m_pstTimersArray){/* dsp_log(MOD_OSTIME, DSP_LOG_ERROR,"[ERROR] OSTIME_SysTimeCallback: Failed to call HeapAlloc with %d Bytes\n",(DWORD) gslSizeLpTimers * sizeof(STOSTIMERENTRY));*/lIndex = 0;pUser->m_lSizeLpTimers = 0;break;}}}pUser->m_pstTimersArray[lIndex++] = *pstTimerEntry;}/* 更新當(dāng)前觸發(fā)時間為下次定時器到的時間 */pstTimerEntry->llTriggerTime += pstTimerEntry->ulDelay;/* 定時器設(shè)置為單次定時器 */if (0 == (pstTimerEntry->ulFlags & OSTIME_PERIODIC)){/* 從定時器鏈表中刪除當(dāng)前的定時器 */*ppstTimerEntry = *ppstNextTimerEntry;HeapFree(pUser->m_hOSTimeHeap, 0, pstTimerEntry);pstTimerEntry = NULL;/* 將當(dāng)前定時器的等待時間設(shè)置為無窮 */dwDeltaTime = INFINITE;}else{/* 計算下次中的時間間隔 */if (pstTimerEntry->llTriggerTime <= llCurTime){/* 當(dāng)定時器需要追趕的時間差超過設(shè)置的時間間隔時,需要將定時器時間戳同步為當(dāng)前系統(tǒng)時間 */if ((unsigned int) (llCurTime - pstTimerEntry->llTriggerTime) > (OSTIME_MAX_DELAY_CYC * pstTimerEntry->ulDelay)){/* dsp_log(MOD_OSTIME, DSP_LOG_INFO,"[ERROR] OSTIME_SysTimeCallback: Reset Trigger time to current system time for diff time[%u]\n",llCurTime - pstTimerEntry->llTriggerTime);*/pstTimerEntry->llTriggerTime = llCurTime;}dwDeltaTime = 0;}else{lgTempTime.QuadPart = pstTimerEntry->llTriggerTime - llCurTime;dwDeltaTime = lgTempTime.LowPart;}}}else{/* 如果當(dāng)前的定時器沒有命中,直接修改定時周期即可 */lgTempTime.QuadPart = pstTimerEntry->llTriggerTime - llCurTime;dwDeltaTime = lgTempTime.LowPart;}/* 更新整個鏈表中的最小等待時間 */dwRetTime = (dwRetTime < dwDeltaTime ? dwRetTime : dwDeltaTime);ppstTimerEntry = ppstNextTimerEntry;}/* 為了防止定時器執(zhí)行過程中進行定時器的刪除,這邊將kill標(biāo)記進行復(fù)位 */if ((HANDLE) NULL != pUser->m_hOsTimeKillEvent){if (0 == ResetEvent(pUser->m_hOsTimeKillEvent)){/* dsp_log(MOD_OSTIME, DSP_LOG_ERROR,"[ERROR] OSTIME_SysTimeCallback: Failed to reset gshOsTimeKillEvent event to stop timer running thread! ErrorCode:%u\n",GetLastError());*/}}LeaveCriticalSection(&pUser->m_OsTime_cs);/* 執(zhí)行定時時間到的回調(diào)函數(shù) */while (lIndex > 0){OSTIME_TriggerCallBack(&pUser->m_pstTimersArray[--lIndex]);}/* 同時同步退出線程的執(zhí)行 */if ((HANDLE) NULL != pUser->m_hOsTimeKillEvent){if (0 == SetEvent(pUser->m_hOsTimeKillEvent)){/*dsp_log(MOD_OSTIME, DSP_LOG_ERROR,"[ERROR] OSTIME_SysTimeCallback: Failed to set gshOsTimeKillEvent event to stop timer running thread! ErrorCode:%u\n",GetLastError());*/}}/* 當(dāng)程序執(zhí)行完成后,將函數(shù)執(zhí)行的時間更新到當(dāng)前的定時器列表中,使得下次命中的時間更加的精確 */EnterCriticalSection(&pUser->m_GetSystemTime_cs);lgTempTime.QuadPart = OsGetTickCount64(arg) - llCurTime;LeaveCriticalSection(&pUser->m_GetSystemTime_cs);dwAdjustTime = lgTempTime.LowPart;if (dwAdjustTime > dwRetTime){dwRetTime = 0;}else{dwRetTime -= dwAdjustTime;}/* 將下次中斷時間間隔返回 */return(dwRetTime/OSTIME_PREC);}/** * 用戶注冊給定時器的定時器回調(diào)函數(shù) * @param [IN] lpTimer 定時器控制塊的地址 * @return 無 */ VOID MsTimer::OSTIME_TriggerCallBack( IN PSTOSTIMERENTRY lpTimer ) {MsTimer* puser = (MsTimer*)(lpTimer->arg);/* 根據(jù)用戶設(shè)定的定時器flag標(biāo)記位確認是否將結(jié)構(gòu)體傳遞給用戶 */if (lpTimer->ulFlags & OSTIME_ADJUST_PERIODIC){STOSTIMERENTRY stOsTimerEntry = *lpTimer;(lpTimer->lpFunc)(lpTimer->ulTimerID, 0, lpTimer->ulUser, 0, (unsigned int) lpTimer);/* 用戶修改了定時器周期后,需要更新定時器控制塊 */if (stOsTimerEntry.ulDelay != lpTimer->ulDelay){EnterCriticalSection(&puser->m_GetSystemTime_cs);for (PSTOSTIMERENTRY pStOsTimerEntry = puser->m_pstOsTimersList; pStOsTimerEntry != NULL; pStOsTimerEntry = pStOsTimerEntry->pstNextOsTimerEntry){if (pStOsTimerEntry->ulTimerID == lpTimer->ulTimerID){/* dsp_log(MOD_OSTIME, DSP_LOG_TRACE,"[INIFO] %d OSTIME_SysTimeCallback: change from %d to %d\n",pStOsTimerEntry->ulTimerID, pStOsTimerEntry->ulDelay, lpTimer->ulDelay);*/pStOsTimerEntry->ulDelay = lpTimer->ulDelay;}}LeaveCriticalSection(&puser->m_GetSystemTime_cs);}}else{(lpTimer->lpFunc)(lpTimer->ulTimerID, 0, lpTimer->ulUser, 0, 0);} }/** * 啟動一個定時器,定時器模塊內(nèi)部實現(xiàn)函數(shù) * @param [IN] ulDelay 定時器的周期,單位ms,范圍必須為澹[1、65535]. * @param [IN] ulResol 為兼容windows操作系統(tǒng)的函數(shù),參數(shù)未啟用。 * @param [IN] lpFunc 回調(diào)函數(shù),必須為LPOSTIMECALLBACK的函數(shù)指針 * @param [IN] ulUser 傳遞給回調(diào)函數(shù)的參數(shù)。 * @param [IN] ulFlags 標(biāo)識當(dāng)前定時器的類型,現(xiàn)在只支持兩種標(biāo)記:OSTIME_KILL_SYNCHRONOUS 當(dāng)前為同步定時器,OstimeKillEvent返回時必須保證不再進行回調(diào)函數(shù)調(diào)用OSTIME_PERIODIC 是否需要周期調(diào)用回調(diào)函數(shù),不設(shè)置則屬于一次性定時器 * @return 定時器ID號,如果失敗,則返回的定時器ID號為0,成功返回非0值 */ unsigned int MsTimer::OSTIME_SetEventInternal( IN unsigned int ulDelay, IN unsigned int ulResol, IN LPOSTIMECALLBACK lpFunc, IN ULONG ulUser, IN unsigned int ulFlags ) {/* 判斷定時器周期的有效性 */if ((ulDelay < OSSYSTIME_MININTERVAL) || (ulDelay > OSSYSTIME_MAXINTERVAL) || (NULL == lpFunc)){/* dsp_log(MOD_OSTIME, DSP_LOG_ERROR,"[ERROR] OSTIME_SetEventInternal: The ulDelay paremeter in OsTimer is invalid\n");*/return 0;}/* 申請一塊定時器控制塊 */PSTOSTIMERENTRY pstNewTimer = (PSTOSTIMERENTRY) HeapAlloc(m_hOSTimeHeap, 0, sizeof(STOSTIMERENTRY));if (NULL == pstNewTimer){/* dsp_log(MOD_OSTIME, DSP_LOG_ERROR,"[ERROR] OSTIME_SetEventInternal: Cann't HeapAlloc a memory for pstTimerEntry contrl\n");*/return 0;}pstNewTimer->ulDelay = ulDelay;EnterCriticalSection(&m_GetSystemTime_cs);pstNewTimer->llTriggerTime = OsGetTickCount64(this) + ulDelay;LeaveCriticalSection(&m_GetSystemTime_cs);pstNewTimer->ulResol = ulResol;pstNewTimer->lpFunc = lpFunc;pstNewTimer->ulUser = ulUser;pstNewTimer->ulFlags = ulFlags;pstNewTimer->arg = this;EnterCriticalSection(&m_OsTime_cs);/* 判斷是否創(chuàng)建同步定時器,如果時同步定時器并且停止事件沒有創(chuàng)建則進行事件創(chuàng)建 */if ((0 != (ulFlags & OSTIME_KILL_SYNCHRONOUS)) && ((HANDLE) NULL == m_hOsTimeKillEvent)){m_hOsTimeKillEvent = CreateEventW(NULL, TRUE, TRUE, NULL);if ((HANDLE) NULL == m_hOsTimeKillEvent){/* dsp_log(MOD_OSTIME, DSP_LOG_ERROR,"[ERROR] OSTIME_SetEventInternal: Failed to create an Time kill Event for pstTimerEntry running! ErrorCode:%u\n",GetLastError());*/LeaveCriticalSection(&m_OsTime_cs);HeapFree(m_hOSTimeHeap, 0, pstNewTimer);pstNewTimer = NULL;return 0;}}pstNewTimer->ulTimerID = OsGenTimerID();if (0 == pstNewTimer->ulTimerID){LeaveCriticalSection(&m_OsTime_cs);HeapFree(m_hOSTimeHeap, 0, pstNewTimer);pstNewTimer = NULL;/* dsp_log(MOD_OSTIME, DSP_LOG_ERROR,"[ERROR] OSTIME_SetEventInternal: Cann't general an timerID for pstTimerEntry contrl\n");*/return 0;}pstNewTimer->pstNextOsTimerEntry = m_pstOsTimersList;m_pstOsTimersList = pstNewTimer;LeaveCriticalSection(&m_OsTime_cs);/* 觸發(fā)一次定時回調(diào)函數(shù)調(diào)用 */if (0 == SetEvent(m_hOsTimeWakeEvent)){/* dsp_log(MOD_OSTIME, DSP_LOG_WARNING,"[WARNING] OSTIME_SetEventInternal: Failed to set gshOsTimeWakeEvent event to the timer running thread! ErrorCode:%u\n",GetLastError());*/}return pstNewTimer->ulTimerID; }/** * 使用C++的map產(chǎn)生一個定時器ID號 * @param [IN] 無 * @return 返回當(dāng)前的定時器ID。0 表示獲取定時器ID失敗 */ unsigned int MsTimer::OsGenTimerID( VOID ) {/*查詢隊列中是否已經(jīng)含有定時器ID號,定時器ID不能為0,同時嘗試查詢的次數(shù)為OSTOTAL_TIMERID_TRYNUM次*/std::map<unsigned int, unsigned int>::iterator iter;EnterCriticalSection(&m_OSTimerID_cs);m_ulCurTimerID++;if (0 == m_ulCurTimerID){m_ulCurTimerID++;}for (unsigned int ulIndex = 0; ulIndex < OSTOTAL_TIMERID_TRYNUM; ulIndex++){iter = m_mapOsTimerID.find(m_ulCurTimerID);if (m_mapOsTimerID.end() != iter){m_ulCurTimerID++;if (0 == m_ulCurTimerID){m_ulCurTimerID++;}}else{/* 將獲得的定時器Timer壓入map隊列 */m_mapOsTimerID.insert(std::pair<unsigned int, unsigned int>(m_ulCurTimerID, m_ulCurTimerID));unsigned int ulTimerIDTmp = m_ulCurTimerID;LeaveCriticalSection(&m_OSTimerID_cs);return ulTimerIDTmp;}}LeaveCriticalSection(&m_OSTimerID_cs);return 0; } /** * 刪除全局隊列中的timerID編號 * @param [IN] ulTimerID需要刪除的定時器ID號 * @return 無 */ VOID MsTimer::OsReleaseTimerID( IN unsigned int ulTimerID ) {EnterCriticalSection(&m_OSTimerID_cs);m_mapOsTimerID.erase(ulTimerID);LeaveCriticalSection(&m_OSTimerID_cs);return;}
總結(jié)
- 上一篇: 线程池重要的类。
- 下一篇: SpringMVC+ZTree实现树形菜