当前位置:网站首页>utils 定时器
utils 定时器
2022-08-03 22:23:00 【Zip-List】
定时器作为常见的工具,要好好掌握。
整体思路
CTimer代表一个loop的线程
CTimerManager是一个CTimer的容器(map<id, CTimer*>)
同时CTimer是一个std::list<TTimerReq>容器。
即
CTimer1: [1(11ms), 3(12ms), 2(13ms), 4(14ms)]
CTimer2: [1(11ms), 3(12ms), 2(13ms), 4(14ms)]
CTimer中根据超时时间从小到大保存着每个回调函数的ID,回调是通过和CTimer绑定的CTimerListener实现的。CTimerListener可以是一个继承自它的单例类对象,可以是一个全局的session_waiting_context对象等等。
typedef struct
{
uint32_t reqId;
TTimeSpec timeout;
} TTimerReq;
头文件
#pragma once
#include <list>
#include <atomic>
#include <string>
#include <pthread.h>
#include <mutex>
using TTimeSpec = struct timespec;
typedef struct
{
uint32_t reqId;
TTimeSpec timeout;
} TTimerReq;
class CTimerListener;
class CTimer
{
public:
CTimer(const std::string &name, uint32_t timerId, CTimerListener *timerListener);
virtual ~CTimer();
bool start(uint32_t msec, uint32_t reqId = 0);
bool stop(uint32_t reqId = 0);
private:
CTimer(const CTimer &);
CTimer &operator=(const CTimer &);
void onTimer(uint32_t reqId);
void onRun();
static void *threadFunc(void *arg);
void addRequest(TTimerReq req);
void notify();
private:
volatile uint32_t mTimerId;
CTimerListener *mTimerListener;
std::mutex mDataMutex;
std::list<TTimerReq> mTimerReqList;
std::string mThreadName;
std::atomic<bool> mThreadExitFlag{
false};
volatile bool mReqFlag;
pthread_t mThread;
pthread_attr_t mThreadAttr;
pthread_mutex_t mThreadmutex;
pthread_condattr_t mCondAttr;
pthread_cond_t mCondition;
};
#pragma once
#include <map>
#include <mutex>
#include <string>
#define TIMER_MGR CTimerManager::getInstance()
class CTimerListener
{
public:
CTimerListener() {
}
virtual ~CTimerListener() {
}
virtual void onTimer(uint32_t id) = 0;
};
class CTimer;
class CTimerManager
{
public:
CTimerManager();
virtual ~CTimerManager();
static CTimerManager *getInstance();
static void destroy();
bool createTimer(const std::string &name, CTimerListener *timerListener);
bool createTimer(const std::string &name, uint32_t id, CTimerListener *timerListener);
bool startTimer(uint32_t id, uint32_t msec, uint32_t sub_id=0);
bool stopTimer(uint32_t id);
private:
CTimerManager(const CTimerManager &);
CTimerManager &operator=(const CTimerManager &);
private:
static CTimerManager *mInstance;
static std::mutex mDataMutex;
CTimer *mTimer;
std::map<uint32_t, CTimer *> mTimerMap;
};
主循环
主循环loop当前队伍头的回调能否执行,如果还不超时就继续条件等待 sleepTime+1ms,下次唤醒时肯定能执行了,也不会造成无效的loop浪费cpu
void CTimer::onRun()
{
// int pri = getpriority(PRIO_PROCESS, gettid());
pthread_setname_np(mThread, mThreadName.c_str());
uint32_t sleepTime = THREAD_INFINITE;
while (!mThreadExitFlag)
{
pthread_mutex_lock(&mThreadmutex);
if (!mReqFlag)
{
if (THREAD_INFINITE != sleepTime && 0 != sleepTime)
{
TTimeSpec awakeTime{
0x00};
getTimeSpec(&awakeTime, sleepTime);
pthread_cond_timedwait(&mCondition, &mThreadmutex, &awakeTime);
}
else
{
pthread_cond_wait(&mCondition, &mThreadmutex);
}
}
mReqFlag = false;
pthread_mutex_unlock(&mThreadmutex);
{
std::unique_lock<std::mutex> lock(mDataMutex);
while (!mTimerReqList.empty())
{
TTimerReq curReq = mTimerReqList.front();
TTimeSpec curTime{
0x00};
getTimeSpec(&curTime, 0);
int tmptime = subTimeSpec(&curReq.timeout, &curTime);
if (tmptime <= 0)
{
mTimerReqList.pop_front();
lock.unlock();
onTimer(curReq.reqId);
lock.lock();
}
else
{
sleepTime = tmptime + 1;
break;
}
}
if (mTimerReqList.empty())
{
sleepTime = THREAD_INFINITE;
}
// lock.unlock();
}
}
}
添加定时器
1 根据超时时间的大小,有序的添加到队伍中。
2 如果是添加在队伍头的定时器,需要发送信号,唤醒条件等待中的主循环,重新设置条件等待唤醒时间
void CTimer::addRequest(TTimerReq req)
{
std::unique_lock<std::mutex> lock(mDataMutex);
bool needNotify = false;
auto iter = mTimerReqList.begin();
for (; iter != mTimerReqList.end(); ++iter)
{
if (iter->reqId == req.reqId)
{
if (iter == mTimerReqList.begin())
{
needNotify = true;
}
iter = mTimerReqList.erase(iter);
break;
}
}
if (!mTimerReqList.empty())
{
for (iter = mTimerReqList.begin(); iter != mTimerReqList.end(); ++iter)
{
if (subTimeSpec(&req.timeout, &iter->timeout) < 0)
{
if (iter == mTimerReqList.begin())
{
needNotify = true;
}
break;
}
}
}
else
{
needNotify = true;
}
mTimerReqList.insert(iter, req);
if (needNotify)
{
notify();
}
}
cpp文件
#include "CTimer.hpp"
#include "CTimerManager.hpp"
CTimerManager *CTimerManager::mInstance = nullptr;
std::mutex CTimerManager::mDataMutex;
CTimerManager::CTimerManager() : mTimer(nullptr)
{
}
CTimerManager::~CTimerManager()
{
if (nullptr != mTimer)
{
delete mTimer;
mTimer = nullptr;
}
else
{
auto iter = mTimerMap.begin();
for (; iter != mTimerMap.end(); ++iter)
{
delete iter->second;
iter->second = nullptr;
}
}
}
CTimerManager *CTimerManager::getInstance()
{
std::unique_lock<std::mutex> lock(mDataMutex);
if (nullptr == mInstance)
{
mInstance = new CTimerManager();
}
return mInstance;
}
void CTimerManager::destroy()
{
std::unique_lock<std::mutex> lock(mDataMutex);
if (nullptr != mInstance)
{
delete mInstance;
mInstance = nullptr;
}
}
bool CTimerManager::createTimer(const std::string &name, CTimerListener *timerListener)
{
std::unique_lock<std::mutex> lock(mDataMutex);
bool ret = false;
if (mTimerMap.empty())
{
if (nullptr == mTimer)
{
mTimer = new CTimer(name, 0, timerListener);
}
if (nullptr != mTimer)
{
ret = true;
}
}
return ret;
}
bool CTimerManager::createTimer(const std::string &name, uint32_t id, CTimerListener *timerListener)
{
std::unique_lock<std::mutex> lock(mDataMutex);
bool ret = false;
if (nullptr == mTimer)
{
if (mTimerMap.find(id) == mTimerMap.end())
{
CTimer *timer = new CTimer(name, id, timerListener);
if (nullptr != timer)
{
mTimerMap[id] = timer;
ret = true;
}
}
else
{
ret = true;
}
}
return ret;
}
bool CTimerManager::startTimer(uint32_t id, uint32_t msec, uint32_t sub_id)
{
std::unique_lock<std::mutex> lock(mDataMutex);
bool ret = false;
if (nullptr != mTimer)
{
mTimer->start(msec, id);
ret = true;
}
else if (mTimerMap.find(id) != mTimerMap.end())
{
mTimerMap[id]->start(msec, sub_id);
ret = true;
}
else
{
}
return ret;
}
bool CTimerManager::stopTimer(uint32_t id)
{
std::unique_lock<std::mutex> lock(mDataMutex);
bool ret = false;
if (nullptr != mTimer)
{
mTimer->stop(id);
ret = true;
}
else if (mTimerMap.find(id) != mTimerMap.end())
{
mTimerMap[id]->stop();
ret = true;
}
else
{
}
return ret;
}
#include <unistd.h>
#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/syscall.h>
#include "CTimer.hpp"
#include "CTimerManager.hpp"
namespace
{
#define THREAD_STACK_SIZE (64 * 1024)
#define THREAD_INFINITE (0xFFFFFFFF)
void getTimeSpec(TTimeSpec *time, int msec)
{
TTimeSpec now{
0x00};
clock_gettime(CLOCK_MONOTONIC, &now);
time->tv_sec = now.tv_sec + msec / 1000;
time->tv_nsec = now.tv_nsec + (msec % 1000) * 1000000;
if (time->tv_nsec >= 1000000000)
{
time->tv_sec++;
time->tv_nsec -= 1000000000;
}
}
int subTimeSpec(TTimeSpec *time1, TTimeSpec *time2)
{
int ms =
time1->tv_sec * 1000 + time1->tv_nsec / 1000000 - (time2->tv_sec * 1000 + time2->tv_nsec / 1000000);
return ms;
}
}
CTimer::CTimer(const std::string &name, uint32_t timerId, CTimerListener *timerListener) : mTimerId(timerId), mTimerListener(timerListener), mTimerReqList(), mThreadName(name), mReqFlag(false)
{
int ret = 0;
// init mutex
ret = pthread_mutex_init(&mThreadmutex, nullptr);
if (0 != ret)
{
// log
}
// init condition variable
pthread_condattr_init(&mCondAttr);
pthread_condattr_setclock(&mCondAttr, CLOCK_MONOTONIC);
ret = pthread_cond_init(&mCondition, &mCondAttr);
if (0 != ret)
{
// log
}
// create thread
pthread_attr_init(&mThreadAttr);
pthread_attr_setstacksize(&mThreadAttr, THREAD_STACK_SIZE);
ret = pthread_create(&mThread, &mThreadAttr, threadFunc, this);
if (0 != ret)
{
// log
}
}
CTimer::~CTimer()
{
if (0 == mThread)
{
return;
}
{
std::unique_lock<std::mutex> lock(mDataMutex);
mTimerReqList.clear();
}
mThreadExitFlag = true;
pthread_cond_signal(&mCondition);
pthread_join(mThread, nullptr);
pthread_mutex_destroy(&mThreadmutex);
pthread_cond_destroy(&mCondition);
pthread_condattr_destroy(&mCondAttr);
pthread_attr_destroy(&mThreadAttr);
}
bool CTimer::start(uint32_t msec, uint32_t reqId)
{
TTimeSpec timeout{
0x00};
getTimeSpec(&timeout, msec);
TTimerReq req = {
reqId, timeout};
addRequest(req);
return true;
}
bool CTimer::stop(uint32_t reqId)
{
std::unique_lock<std::mutex> lock(mDataMutex);
bool needNotify = false;
auto iter = mTimerReqList.begin();
for (; iter != mTimerReqList.end(); ++iter)
{
if (iter->reqId == reqId)
{
if (iter == mTimerReqList.begin())
{
needNotify = true;
}
mTimerReqList.erase(iter);
break;
}
}
if (needNotify)
{
notify();
}
return true;
}
void CTimer::onTimer(uint32_t reqId)
{
if (nullptr != mTimerListener)
{
mTimerListener->onTimer(reqId);
}
}
void CTimer::onRun()
{
// int pri = getpriority(PRIO_PROCESS, gettid());
pthread_setname_np(mThread, mThreadName.c_str());
uint32_t sleepTime = THREAD_INFINITE;
while (!mThreadExitFlag)
{
pthread_mutex_lock(&mThreadmutex);
if (!mReqFlag)
{
if (THREAD_INFINITE != sleepTime && 0 != sleepTime)
{
TTimeSpec awakeTime{
0x00};
getTimeSpec(&awakeTime, sleepTime);
pthread_cond_timedwait(&mCondition, &mThreadmutex, &awakeTime);
}
else
{
pthread_cond_wait(&mCondition, &mThreadmutex);
}
}
mReqFlag = false;
pthread_mutex_unlock(&mThreadmutex);
{
std::unique_lock<std::mutex> lock(mDataMutex);
while (!mTimerReqList.empty())
{
TTimerReq curReq = mTimerReqList.front();
TTimeSpec curTime{
0x00};
getTimeSpec(&curTime, 0);
int tmptime = subTimeSpec(&curReq.timeout, &curTime);
if (tmptime <= 0)
{
mTimerReqList.pop_front();
lock.unlock();
onTimer(curReq.reqId);
lock.lock();
}
else
{
sleepTime = tmptime + 1;
break;
}
}
if (mTimerReqList.empty())
{
sleepTime = THREAD_INFINITE;
}
// lock.unlock();
}
}
}
void *CTimer::threadFunc(void *arg)
{
if (nullptr == arg)
{
return nullptr;
}
static_cast<CTimer *>(arg)->onRun();
pthread_exit(nullptr);
}
void CTimer::addRequest(TTimerReq req)
{
std::unique_lock<std::mutex> lock(mDataMutex);
bool needNotify = false;
auto iter = mTimerReqList.begin();
for (; iter != mTimerReqList.end(); ++iter)
{
if (iter->reqId == req.reqId)
{
if (iter == mTimerReqList.begin())
{
needNotify = true;
}
iter = mTimerReqList.erase(iter);
break;
}
}
if (!mTimerReqList.empty())
{
for (iter = mTimerReqList.begin(); iter != mTimerReqList.end(); ++iter)
{
if (subTimeSpec(&req.timeout, &iter->timeout) < 0)
{
if (iter == mTimerReqList.begin())
{
needNotify = true;
}
break;
}
}
}
else
{
needNotify = true;
}
mTimerReqList.insert(iter, req);
if (needNotify)
{
notify();
}
}
void CTimer::notify()
{
pthread_mutex_lock(&mThreadmutex);
mReqFlag = true;
pthread_cond_signal(&mCondition);
pthread_mutex_unlock(&mThreadmutex);
}
用法
CTimerManager中有一个CTimer和一个容器,对应着是否要启动多个组。轻量级只需要启一个相关的定时器,处理和该定时器对应的多个回调ID。多个组就对应启多个线程。
CTimer *mTimer;
std::map<uint32_t, CTimer *> mTimerMap;
边栏推荐
猜你喜欢
CAS: 773888-45-2_BIOTIN ALKYNE_Biotin-alkynyl
[N1CTF 2018] eating_cms
CAS:908007-17-0_Biotin-azide_Biotin azide
PowerMockup 4.3.4::::Crack
Diazo Biotin-PEG3-DBCO|重氮化合物修饰生物素-三聚乙二醇-二苯并环辛炔
嵌入式系统:时钟
LabVIEW code generation error 61056
如何创建一个Web项目
FVCOM 3D Numerical Simulation of Hydrodynamics, Water Exchange, Dispersion and Transport of Oil Spills丨FVCOM Model Watershed, Numerical Simulation Method of Marine Water Environment
IO thread process -> thread synchronization mutual exclusion mechanism -> day6
随机推荐
JPA Native Query(本地查询)及查询结果转换
一些思考:腾讯股价为何持续都低
Diazo Biotin-PEG3-DBCO|重氮化合物修饰生物素-三聚乙二醇-二苯并环辛炔
《数字经济全景白皮书》金融数字用户篇 重磅发布!
Cisco ike2 IPSec configuration
嵌入式系统:概述
21天打卡挑战学习MySQL—Day第一周 第一篇
七夕快乐!
授人以渔 - 如何自行查询任意 SAP UI5 控件属性的文档和技术实现细节试读版
480. Sliding Window Median
线上服务器老是卡,该如何优化?
UVa 10003 - Cutting Sticks (White Book, Interval DP)
超级实用网站+公众号合集
函数,递归以及dom简单操作
Boss: There are too many systems in the company, can you realize account interoperability?
October 2019 Twice SQL Injection
Kubernetes入门到精通-Operator 模式
如何设计 DAO 的 PoW 评判标准 并平衡不可能三角
win10系统下yolov5-V6.1版本的tensorrt部署细节教程及bug修改
node连接mysql数据库报错:Client does not support authentication protocol requested by server