1、本文展示秒级定时器的源码,源码是封装成C++类,然后再次封装成API函数的方式。
用户开发手册地址:https://blog.csdn.net/freeland008/article/details/107508749
2、TimerVM.h和TimerVM.cpp是用c++类的方式实现了秒级时钟的封装,TimerMng.h、TimerMng.cpp实现了二次封装,更方便开发人员直接使用。
3、总体实现思路是使用双时间轮数组交换的方式。
4、TimerVM.h
#ifndef TIMERVM_H
#define TIMERVM_H
#include <time.h>
typedef void* HANDLE;
typedef struct _TIMERITEM
{
unsigned int dwTimes;
unsigned int dwTimeOut;
time_t dtExpire;
void* fp;
void* pPara;
void* pPosArray;
_TIMERITEM* pPrev;
_TIMERITEM* pNext;
}TIMERITEM;
typedef TIMERITEM* LPTIMERITEM;
typedef struct _TIMERARRAY
{
time_t dtStart;
HANDLE* hArray;
_TIMERARRAY()
{
dtStart = 0;
hArray = NULL;
}
}TIMERARRAY;
typedef TIMERARRAY* LPTIMERARRAY;
class CTimerMng
{
private:
TIMERARRAY m_pTimerArrayA;
TIMERARRAY m_pTimerArrayB;
time_t m_dtLastCheck;
int m_nArraySize;
public:
LPTIMERARRAY m_pArrayOld;
LPTIMERARRAY m_pArrayNew;
private:
size_t m_nCount;
int m_nTimerOutCount;
int m_nSetTimerCount;
int m_nResetCycleTimerCount;
int m_nResetOverTimerCount;
public:
LPTIMERITEM m_pResetList;
LPTIMERITEM m_pOverList;
public:
CTimerMng();
~CTimerMng();
public:
int Init(int nArraySize, time_t dtNow);
int Destroy();
LPTIMERITEM SetTimer(time_t dtNow, unsigned int dwTimeOut, unsigned int dwTimes, void* fp, void* pPara);
void ResetTimerCycle(LPTIMERITEM pItem);
void ResetTimerOver(LPTIMERITEM pItem);
void KillTimer(LPTIMERITEM pItem);
void CheckTimeOut(time_t dtNow);
void OnProcTimeOut(LPTIMERITEM pItem, time_t dtNow);
size_t GetCount(){return m_nCount;};
};
#endif
5、TimerVM.cpp
#include <stdio.h>
#include <stdlib.h>
#include "TimerVM.h"
#include "TimerMng.h"
CTimerMng :: CTimerMng()
{
m_nCount = 0;
m_nTimerOutCount = 0;
m_nSetTimerCount = 0;
m_nResetCycleTimerCount = 0;
m_nResetOverTimerCount = 0;
m_dtLastCheck = 0;
m_pResetList = NULL;
m_pOverList = NULL;
m_pTimerArrayA.hArray = NULL;
m_pTimerArrayB.hArray = NULL;
}
CTimerMng :: ~CTimerMng()
{
Destroy();
}
int CTimerMng :: Init(int nArraySize, time_t dtNow)
{
m_nArraySize = nArraySize;
m_pTimerArrayA.hArray = new HANDLE[m_nArraySize];
int i;
for (i = 0; i < m_nArraySize; i++)
{
m_pTimerArrayA.hArray[i] = NULL;
}
m_pTimerArrayB.hArray = new HANDLE[m_nArraySize];
for (i = 0; i < m_nArraySize; i++)
{
m_pTimerArrayB.hArray[i] = NULL;
}
m_pArrayOld = &m_pTimerArrayA;
m_pArrayNew = &m_pTimerArrayB;
m_pArrayOld->dtStart = dtNow;
m_pArrayNew->dtStart = m_pArrayOld->dtStart + m_nArraySize;
m_dtLastCheck = dtNow;
//
return 0;
}
/*
void CTimerMng :: Align(time_t dtNow)
{
m_pArrayOld->dtStart = dtNow;
m_pArrayNew->dtStart = m_pArrayOld->dtStart + m_nArraySize;
m_dtLastCheck = dtNow;
}*/
int CTimerMng :: Destroy()
{
if(m_pTimerArrayA.hArray != NULL)
{
delete[] m_pTimerArrayA.hArray;
m_pTimerArrayA.hArray = NULL;
}
if(m_pTimerArrayB.hArray != NULL)
{
delete[] m_pTimerArrayB.hArray;
m_pTimerArrayB.hArray = NULL;
}
return 0;
}
LPTIMERITEM CTimerMng :: SetTimer(time_t dtNow, unsigned int nElapse, unsigned int dwTimes, void* fp, void* pPara)
{
if(nElapse == 0)
{
return NULL;
}
time_t dtExpire;
dtExpire = dtNow + nElapse;
LPTIMERITEM pItem;
pItem = (LPTIMERITEM)malloc(sizeof(TIMERITEM));
pItem->dtExpire = dtExpire;
pItem->dwTimeOut = nElapse;
pItem->dwTimes = dwTimes;
pItem->pPara = pPara;
pItem->fp = fp;
pItem->pPrev = NULL;
pItem->pNext = NULL;
void* pAddr;
if(dtExpire >= m_pArrayNew->dtStart)
{
int nIndex;
nIndex = dtExpire - m_pArrayNew->dtStart;
nIndex = nIndex%m_nArraySize;
if(m_pArrayNew->hArray[nIndex] == NULL)
{
m_pArrayNew->hArray[nIndex] = pItem;
}
else
{
LPTIMERITEM pTmp;
pTmp = (LPTIMERITEM)(m_pArrayNew->hArray[nIndex]);
pItem->pNext = pTmp;
pTmp->pPrev = pItem;
m_pArrayNew->hArray[nIndex] = pItem;
}
pAddr = &(m_pArrayNew->hArray[nIndex]);
}
else
{
int nIndex;
nIndex = dtExpire - m_pArrayOld->dtStart;
if(m_pArrayOld->hArray[nIndex] == NULL)
{
m_pArrayOld->hArray[nIndex] = pItem;
}
else
{
LPTIMERITEM pTmp;
pTmp = (LPTIMERITEM)(m_pArrayOld->hArray[nIndex]);
pItem->pNext = pTmp;
pTmp->pPrev = pItem;
m_pArrayOld->hArray[nIndex] = pItem;
}
pAddr = &(m_pArrayOld->hArray[nIndex]);
}
//
pItem->pPosArray = pAddr;
m_nCount++;
m_nSetTimerCount++;
return pItem;
}
void CTimerMng :: ResetTimerOver(LPTIMERITEM pItem)
{
void* pAddr;
if(pItem->dtExpire >= m_pArrayNew->dtStart)
{
int nIndex;
nIndex = pItem->dtExpire - m_pArrayNew->dtStart;
nIndex = nIndex%m_nArraySize;
if(m_pArrayNew->hArray[nIndex] == NULL)
{
m_pArrayNew->hArray[nIndex] = pItem;
pItem->pPrev = NULL;
pItem->pNext = NULL;
}
else
{
LPTIMERITEM pTmp;
pTmp = (LPTIMERITEM)(m_pArrayNew->hArray[nIndex]);
pItem->pNext = pTmp;
pItem->pPrev = NULL;
pTmp->pPrev = pItem;
m_pArrayNew->hArray[nIndex] = pItem;
}
pAddr = &(m_pArrayNew->hArray[nIndex]);
}
else
{
int nIndex;
nIndex = pItem->dtExpire - m_pArrayOld->dtStart;
if(m_pArrayOld->hArray[nIndex] == NULL)
{
m_pArrayOld->hArray[nIndex] = pItem;
pItem->pPrev = NULL;
pItem->pNext = NULL;
}
else
{
LPTIMERITEM pTmp;
pTmp = (LPTIMERITEM)(m_pArrayOld->hArray[nIndex]);
pItem->pNext = pTmp;
pItem->pPrev = NULL;
pTmp->pPrev = pItem;
m_pArrayOld->hArray[nIndex] = pItem;
}
pAddr = &(m_pArrayOld->hArray[nIndex]);
}
pItem->pPosArray = pAddr;
m_nResetOverTimerCount++;
}
void CTimerMng :: ResetTimerCycle(LPTIMERITEM pItem)
{
time_t dtExpire;
dtExpire = pItem->dtExpire + pItem->dwTimeOut;
//
void* pAddr;
if(dtExpire >= m_pArrayNew->dtStart)
{
int nIndex;
nIndex = dtExpire - m_pArrayNew->dtStart;
nIndex = nIndex%m_nArraySize;
if(m_pArrayNew->hArray[nIndex] == NULL)
{
m_pArrayNew->hArray[nIndex] = pItem;
pItem->pPrev = NULL;
pItem->pNext = NULL;
}
else
{
LPTIMERITEM pTmp;
pTmp = (LPTIMERITEM)(m_pArrayNew->hArray[nIndex]);
pItem->pNext = pTmp;
pItem->pPrev = NULL;
pTmp->pPrev = pItem;
m_pArrayNew->hArray[nIndex] = pItem;
}
pAddr = &(m_pArrayNew->hArray[nIndex]);
}
else
{
int nIndex;
nIndex = dtExpire - m_pArrayOld->dtStart;
if(m_pArrayOld->hArray[nIndex] == NULL)
{
m_pArrayOld->hArray[nIndex] = pItem;
pItem->pPrev = NULL;
pItem->pNext = NULL;
}
else
{
LPTIMERITEM pTmp;
pTmp = (LPTIMERITEM)(m_pArrayOld->hArray[nIndex]);
pItem->pNext = pTmp;
pItem->pPrev = NULL;
pTmp->pPrev = pItem;
m_pArrayOld->hArray[nIndex] = pItem;
}
pAddr = &(m_pArrayOld->hArray[nIndex]);
}
//
pItem->dtExpire = dtExpire;
pItem->pPosArray = pAddr;
m_nResetCycleTimerCount++;
}
void CTimerMng :: KillTimer(LPTIMERITEM pItem)
{
void* pAddr;
pAddr = pItem->pPosArray;
if(pItem->pPrev == NULL)
{
if(pItem->pNext == NULL)
{
*(size_t *)pAddr = NULL;
}
else
{
LPTIMERITEM pNext;
pNext = pItem->pNext;
pNext->pPrev = NULL;
*(size_t *)pAddr = (size_t)pNext;
}
}
else
{
if(pItem->pNext == NULL)
{
LPTIMERITEM pPrev;
pPrev = pItem->pPrev;
pPrev->pNext = NULL;
}
else
{
LPTIMERITEM pNext;
pNext = pItem->pNext;
LPTIMERITEM pPrev;
pPrev = pItem->pPrev;
pPrev->pNext = pNext;
pNext->pPrev = pPrev;
}
}
free(pItem);
m_nCount--;
}
void CTimerMng :: CheckTimeOut(time_t dtNow)
{
if(dtNow >= m_pArrayNew->dtStart)
{
if(m_dtLastCheck < m_pArrayNew->dtStart)
{
time_t dtTime;
for(dtTime = m_dtLastCheck + 1; dtTime < m_pArrayNew->dtStart; dtTime++)
{
int nIndex;
nIndex = dtTime - m_pArrayOld->dtStart;
if(nIndex >= m_nArraySize || nIndex < 0)
{
break;
}
HANDLE hList;
hList = m_pArrayOld->hArray[nIndex];
if(hList != NULL)
{
OnProcTimeOut((LPTIMERITEM)hList, dtNow);
m_pArrayOld->hArray[nIndex] = NULL;
}
}
for(dtTime = m_pArrayNew->dtStart; dtTime <= dtNow; dtTime++)
{
int nIndex;
nIndex = dtTime - m_pArrayNew->dtStart;
if(nIndex >= m_nArraySize || nIndex < 0)
{
break;
}
HANDLE hList;
hList = m_pArrayNew->hArray[nIndex];
if(hList != NULL)
{
OnProcTimeOut((LPTIMERITEM)hList, dtNow);
m_pArrayNew->hArray[nIndex] = NULL;
}
}
}
else
{
time_t dtTime;
for(dtTime = m_dtLastCheck + 1; dtTime <= dtNow; dtTime++)
{
int nIndex;
nIndex = dtTime - m_pArrayNew->dtStart;
if(nIndex >= m_nArraySize || nIndex < 0)
{
break;
}
HANDLE hList;
hList = m_pArrayNew->hArray[nIndex];
if(hList != NULL)
{
OnProcTimeOut((LPTIMERITEM)hList, dtNow);
m_pArrayNew->hArray[nIndex] = NULL;
}
}
}
//
LPTIMERARRAY pTmp;
pTmp = m_pArrayOld;
m_pArrayOld = m_pArrayNew;
m_pArrayNew = pTmp;
m_pArrayNew->dtStart = m_pArrayOld->dtStart + m_nArraySize;
//
}
else
{
time_t dtTime;
for(dtTime = m_dtLastCheck + 1; dtTime <= dtNow; dtTime++)
{
int nIndex;
nIndex = dtTime - m_pArrayOld->dtStart;
if(nIndex >= m_nArraySize || nIndex < 0)
{
break;
}
HANDLE hList;
hList = m_pArrayOld->hArray[nIndex];
if(hList != NULL)
{
OnProcTimeOut((LPTIMERITEM)hList, dtNow);
m_pArrayOld->hArray[nIndex] = NULL;
}
}
}
m_dtLastCheck = dtNow;
//
while(m_pResetList != NULL)
{
LPTIMERITEM pItem;
pItem = m_pResetList;
m_pResetList = m_pResetList->pNext;
ResetTimerCycle(pItem);
}
while(m_pOverList != NULL)
{
LPTIMERITEM pItem;
pItem = m_pOverList;
m_pOverList = m_pOverList->pNext;
ResetTimerOver(pItem);
}
}
void CTimerMng :: OnProcTimeOut(LPTIMERITEM pItem, time_t dtNow)
{
while(pItem != NULL)
{
LPTIMERITEM pTmp;
pTmp = pItem->pNext;
if(dtNow < pItem->dtExpire)
{
if(m_pOverList == NULL)
{
m_pOverList = pItem;
m_pOverList->pNext = NULL;
}
else
{
pItem->pNext = m_pOverList;
m_pOverList = pItem;
}
pItem = pItem->pNext;
pItem = pTmp;
continue;
}
//
LPTIMEROUTPROC(pItem->fp)(this, pItem, pItem->pPara);
//
if(pItem->dwTimes != 0xFFFFFFFF)
{
pItem->dwTimes--;
}
if(pItem->dwTimes > 0)
{
if(m_pResetList == NULL)
{
m_pResetList = pItem;
m_pResetList->pNext = NULL;
}
else
{
pItem->pNext = m_pResetList;
m_pResetList = pItem;
}
pItem = pItem->pNext;
pItem = pTmp;
continue;
}
//if(bAutoRelease == true)
//{
//MMFree(pItem, 0);
free(pItem);
m_nCount--;
//}
pItem = pTmp;
m_nTimerOutCount++;
}
}
6、TimerMng.h
#ifndef TIMERMNG_H
#define TIMERMNG_H
#define TVMAPI extern "C" __declspec(dllexport)
typedef void* HANDLE;
typedef void (* LPTIMEROUTPROC)(HANDLE hTimerVM, HANDLE hTimerItem, void* pPara);
TVMAPI HANDLE TVSysCreate(int nArraySize, time_t dtNow);
TVMAPI int TVSysDestroy(HANDLE hTimerVM);
TVMAPI HANDLE TVSetTimerCycle(HANDLE hTimerVM, time_t dtNow, unsigned int dwCycle, unsigned int nTimes, LPTIMEROUTPROC pProc, void* pPara);
TVMAPI HANDLE TVSetTimerAtTime(HANDLE hTimerVM, time_t dtNow, char* sDateTime, LPTIMEROUTPROC pProc, void* pPara);
TVMAPI void TVKillTimer(HANDLE hTimerVM, HANDLE hTimerItem);
TVMAPI size_t TVGetCount(HANDLE hTimerVM);
TVMAPI void TVCheckTimeOut(HANDLE hTimerVM, time_t dtNow);
#endif
7、TimerMng.cpp
#include "TimerVM.h"
#include "TimerMng.h"
#include <time.h>
#include <string.h>
#include <stdlib.h>
TVMAPI HANDLE TVSysCreate(int nArraySize, time_t dtNow)
{
if(nArraySize <= 1)
{
return NULL;
}
CTimerMng* pTimerMng;
pTimerMng = new CTimerMng;
pTimerMng->Init(nArraySize, dtNow);
return pTimerMng;
}
TVMAPI int TVSysDestroy(HANDLE hTimerVM)
{
CTimerMng* pTimerMng;
pTimerMng = (CTimerMng *)hTimerVM;
pTimerMng->Destroy();
delete pTimerMng;
return 0;
}
TVMAPI HANDLE TVSetTimerCycle(HANDLE hTimerVM, time_t dtNow, unsigned int nElapse, unsigned int nTimes, LPTIMEROUTPROC pProc, void* pPara)
{
CTimerMng* pTimerMng;
pTimerMng = (CTimerMng *)hTimerVM;
return(pTimerMng->SetTimer(dtNow, nElapse, nTimes, pProc, pPara));
}
TVMAPI HANDLE TVSetTimerAtTime(HANDLE hTimerVM, time_t dtNow, char* sExpire, LPTIMEROUTPROC pProc, void* pPara)
{
CTimerMng* pTimerMng;
pTimerMng = (CTimerMng *)hTimerVM;
char sPart[5];
tm SystemTime;
memcpy(sPart, sExpire, 4);
sPart[4] = '\0';
SystemTime.tm_year = atoi(sPart) - 1900;
strncpy(sPart, sExpire + 4, 2);
sPart[2] = '\0';
SystemTime.tm_mon = atoi(sPart) - 1;
strncpy(sPart, sExpire + 6, 2);
sPart[2] = '\0';
SystemTime.tm_mday = atoi(sPart);
strncpy(sPart, sExpire + 8, 2);
sPart[2] = '\0';
SystemTime.tm_hour = atoi(sPart);
strncpy(sPart, sExpire + 10, 2);
sPart[2] = '\0';
SystemTime.tm_min = atoi(sPart);
strncpy(sPart, sExpire + 12, 2);
sPart[2] = '\0';
SystemTime.tm_sec = atoi(sPart);
SystemTime.tm_isdst = 0;
time_t dtExpire;
dtExpire = mktime(&SystemTime);
if(dtExpire <= dtNow)
{
return NULL;
}
return(pTimerMng->SetTimer(dtNow, dtExpire - dtNow, 1, pProc, pPara));
}
TVMAPI void TVKillTimer(HANDLE hTimerVM, HANDLE hTimerItem)
{
CTimerMng* pTimerMng;
pTimerMng = (CTimerMng *)hTimerVM;
pTimerMng->KillTimer((LPTIMERITEM)hTimerItem);
}
TVMAPI size_t TVGetCount(HANDLE hTimerVM)
{
CTimerMng* pTimerMng;
pTimerMng = (CTimerMng *)hTimerVM;
return pTimerMng->GetCount();
}
TVMAPI void TVCheckTimeOut(HANDLE hTimerVM, time_t dtNow)
{
CTimerMng* pTimerMng;
pTimerMng = (CTimerMng *)hTimerVM;
pTimerMng->CheckTimeOut(dtNow);
}