在C++11之前,标准库中没有提供原生的定时器功能
启动定时器任务时去创建一个新的线程,并在指定的时间间隔后执行传入的任务函数 task
。可以根据参数来控制是否循环执行任务。任务执行的过程中,通过条件变量和互斥锁来控制线程的等待和唤醒。
#ifndef CTIMER_H
#define CTIMER_H
#include
#include
#include
#include
#include
#include
#include
#include
class CTimer
{
public:
CTimer(const std::string sTimerName = ""); //构造定时器,附带名称
~CTimer();
/**
开始运行定时器
@param msTime 延迟运行(单位ms)
@param task 任务函数接口
@param bLoop 是否循环(默认执行1次)
@return true:已准备执行,否则失败
*/
bool Start(unsigned int msTime, std::function task, bool bLoop = false);
/**
取消定时器,同步定时器无法取消(若任务代码已执行则取消无效)
*/
void Cancel();
/**
异步执行一次任务
@param msTime 延迟及间隔时间(毫秒)
@param fun 函数接口或lambda代码块
@param args 参数
@return true:已准备执行,否则失败
*/
template
bool AsyncOnce(int msTime, callable&& fun, arguments&&... args) {
std::function::type()> task(std::bind(std::forward(fun), std::forward(args)...));
return Start(msTime, task, false);
}
/**
异步循环执行任务
@param msTime 延迟及间隔时间(毫秒)
@param fun 函数接口或lambda代码块
@param args 参数
@return true:已准备执行,否则失败
*/
template
bool AsyncLoop(int msTime, callable&& fun, arguments&&... args) {
std::function::type()> task(std::bind(std::forward(fun), std::forward(args)...));
return Start(msTime, task, true);
}
public:
//获取时间戳(毫秒)
static uint64_t Timestamp();
//获取格式化时间
static std::string FormatTime(const std::string sFormat = "%Y-%m-%d %H:%M:%S");
//获取UTC时间
static struct tm *UTCTime(long long secTime = 0);
//获取UTC时间(秒)
static int64_t UTCTime();
//获取与0时区的时差(以秒为单位)
static int TimeDifFrimGMT();
private:
void DeleteThread(); //删除任务线程
public:
int m_nCount = 0; //循环次数
int m_nTag = 0; //定时器标签
private:
std::string m_sName; //定时器名称
std::atomic_bool m_bExpired; //装载的任务是否已经过期
std::atomic_bool m_bTryExpired; //装备让已装载的任务过期(标记)
std::atomic_bool m_bLoop; //是否循环
std::thread *m_Thread = nullptr;
std::mutex m_ThreadLock;
std::condition_variable_any m_ThreadCon;
};
#endif // CTIMER_H
#include "ctimer.h"
#include
#include
#include
#include
CTimer::CTimer(const std::string sTimerName):m_bExpired(true), m_bTryExpired(false), m_bLoop(false)
{
m_sName = sTimerName;
}
CTimer::~CTimer()
{
m_bTryExpired = true; //尝试使任务过期
DeleteThread();
}
bool CTimer::Start(unsigned int msTime, std::function task, bool bLoop)
{
if (!m_bExpired || m_bTryExpired) return false; //任务未过期(即内部仍在存在或正在运行任务)
m_bExpired = false;
m_bLoop = bLoop;
m_nCount = 0;
DeleteThread();
m_Thread = new std::thread([this, msTime, task]()
{
while (!m_bTryExpired)
{
m_ThreadCon.wait_for(m_ThreadLock, std::chrono::milliseconds(msTime)); //休眠
if (!m_bTryExpired)
{
task(); //执行任务
m_nCount ++;
if (!m_bLoop)
{
break;
}
}
}
m_bExpired = true; //任务执行完成(表示已有任务已过期)
m_bTryExpired = false; //为了下次再次装载任务
});
return true;
}
void CTimer::Cancel()
{
if (m_bExpired || m_bTryExpired || !m_Thread)
{
return;
}
m_bTryExpired = true;
}
void CTimer::DeleteThread()
{
if (m_Thread)
{
m_ThreadCon.notify_all(); //休眠唤醒
m_Thread->join(); //等待线程退出
delete m_Thread;
m_Thread = nullptr;
}
}
uint64_t CTimer::Timestamp()
{
uint64_t msTime = 0;
struct timespec abstime;
clock_gettime(CLOCK_REALTIME, &abstime);
msTime = ((uint64_t)abstime.tv_sec) * 1000 + ((uint64_t)abstime.tv_nsec) / 1000000; //需要强制转long long
return msTime;
}
std::string CTimer::FormatTime(const std::string sFormat)
{
time_t timep;
time (&timep);
char tmp[64];
strftime(tmp, sizeof(tmp), sFormat.c_str(), localtime(&timep));
return std::string(tmp);
}
struct tm *CTimer::UTCTime(long long secTime)
{
time_t timep;
if (secTime) {
timep = secTime;
} else {
time (&timep);
}
struct tm *data = gmtime(&timep);
data->tm_year += 1900;
data->tm_mon += 1;
return data;
}
int64_t CTimer::UTCTime()
{
int64_t msTime = 0;
struct timespec abstime;
clock_gettime(CLOCK_REALTIME, &abstime);
msTime = (int64_t)abstime.tv_sec;
return msTime;
}
int CTimer::TimeDifFrimGMT()
{
time_t now = time(NULL);
struct tm *gmTime = gmtime(&now);
if (gmTime)
{
return (int)difftime(now, mktime(gmTime));
}
return 0;
}
int main()
{
/* 方式1 延迟10毫秒执行1次 */
CTimer *pTimer = new CTimer("定时器1");
pTimer->AsyncOnce(10, [](void *userData) //
{
CPCenterCtl *pCenterCtl = static_cast(userData); //CPCenterCtl是当前类
if (pCenterCtl)
{
CPrintf("这是一个定时器");
}
}, this);
/* 方式2 异步循环执行,间隔时间10毫秒 */
void CPCenterCtl::didHeartbeatThread(void *arg); //定时器任务函数
CTimer *pTimer = new CTimer("定时器2");
pTimer->AsyncLoop(10, didHeartbeatThread, this);
/* 方式3 异步循环执行,间隔时间10毫秒:*/
CTimer *pTimer = new CTimer("定时器3");
pTimer->AsyncLoop(10, [](JMCPCenterCtl *self)
{
printf(“这是一个10毫秒触发的定时器”);
}, this);
/* 方式4 异步循环执行,间隔时间1秒 */
int a = 1;
int b = 2;
int sum = 0;
CTimer *pTimer = new CTimer("定时器4");
pTimer->AsyncLoop(1000, [](void *self, int a, int b, int *sum)
{
*sum = a + b + *sum;
printf("累加 sum += a + b + *sum: %d\n", *sum);
}, this, a, b , &sum);
/* 打印:
累加 sum += a + b + *sum: 3
累加 sum += a + b + *sum: 6
累加 sum += a + b + *sum: 9
累加 sum += a + b + *sum: 12 */
}