定时器SDK
定时器是一切SDK的根本,欲写SDK必先确定定时器,定时器效率的高低决定着SDK函数的效率,下面是我个人写的Linux C++服务器端进程SDK中的定时器,部分参照了ACE和RocketMQ定时器的思想,欢迎大家拍砖,一起改进,共同进步。
#ifndef _TIME_THREAD_H
#define _TIME_THREAD_H
#include <list>
#include <map>
class TimerHandler
{
public:
TimerHandler()
{
}
virtual ~TimerHandler()
{
}
virtual void OnTimeOut(unsigned int timerID,void * pOtherArg) = 0;
};
typedef struct tagTimerlnfo
{
unsigned int id;
unsigned int elapse;
int outTime;// 初始化可以为负数,这样就可以延迟启动了
bool persistent;
TimerHandler * pTimerHandler;
void * pOtherArg;
}TimerInfo;
class TimerThread
{
public:
TimerThread();
~TimerThread();
void Start();
void Close();
unsigned int RegisterTimer(unsigned int initialDelay, unsigned int elapse, TimerHandler *pHandler, void * pOtherArg, bool persistent = true);
bool UnRegisterTimer(unsigned int timerId);
bool ResetTimer(unsigned int timerId);
bool IsRunning(){return m_bIsRunning;}
private:
void CheckTimeOut(unsigned int elapse, std::list<TimerInfo>& timerList, int& minWaitTime);
unsigned int GetNextTimerID();
static void* ThreadRoute(void* pArg);
private:
unsigned int s_nextTimerID;
std::map<unsigned int, TimerInfo> m_timers;
pthread_mutex_t m_mutex;
pthread_mutex_t m_startMutex;
pthread_cond_t m_cond;
bool m_bClosed;
bool m_bIsRunning;
pthread_t m_threadId;
};
#endif
#include <string.h>
#include <errno.h>
#include "log.h"
#include "common.h"
#include "TimeThread.h"
TimerThread::TimerThread():m_bClosed(false)
{
s_nextTimerID = 0;
pthread_cond_init(&m_cond,NULL);
pthread_mutex_init(&m_mutex,NULL);
pthread_mutex_init(&m_startMutex,NULL);
m_bIsRunning = false;
}
TimerThread::~TimerThread()
{
pthread_cond_destroy(&m_cond);
pthread_mutex_destroy(&m_mutex);
pthread_mutex_destroy(&m_startMutex);
}
void* TimerThread::ThreadRoute(void* pArg)
{
TimerThread *pTimerThread = (TimerThread*)pArg;
unsigned long long lastCheckTime = GetCurrentTimeMillis();
unsigned long long currentCheckTime = lastCheckTime;
int delayTime = 0;
std::list<TimerInfo> timerList;
while (!pTimerThread->m_bClosed)
{
currentCheckTime = GetCurrentTimeMillis();
unsigned int elapse = (unsigned int)(currentCheckTime - lastCheckTime);
timerList.clear();
pTimerThread->CheckTimeOut(elapse,timerList,delayTime);
if (!timerList.empty())
{
std::list<TimerInfo>::iterator it = timerList.begin();
for (; it != timerList.end(); it++)
{
it->pTimerHandler->OnTimeOut(it->id,it->pOtherArg);
//外部释放
/*
if (it->persistent == false)
{
delete it->pTimerHandler;
}
*/
}
}
unsigned long long checkEndTime = GetCurrentTimeMillis();
lastCheckTime = currentCheckTime;
int sleepTime = delayTime - (int)(checkEndTime -currentCheckTime);
if (sleepTime <= 0)
{
sleepTime = 0;
}
else
{
//usleep(sleepTime * 1000);
//struct timespec tv;
//tv.tv_sec = sleepTime / 1000;
//tv.tv_nsec = (sleepTime % 1000) * 1000000;
//nanosleep(&tv, 0);
pthread_mutex_lock(&pTimerThread->m_mutex);
struct timespec abstime = CalcAbsTime(sleepTime);
pthread_cond_timedwait(&pTimerThread->m_cond, &pTimerThread->m_mutex, &abstime);
pthread_mutex_unlock(&pTimerThread->m_mutex);
}
}
pTimerThread->m_bIsRunning = false;
return 0;
}
void TimerThread::Start()
{
pthread_mutex_lock(&m_startMutex);//同一个定时器避免启动两次
if (!m_bIsRunning)
{
pthread_attr_t attr;
int retcode = 0;
retcode = pthread_attr_init(&attr);
if(retcode != 0)
{
pthread_mutex_unlock(&m_startMutex);
nDebugLog(LOG_PRIORITY_ERROR, "pthread_attr_init failed:%s!",strerror(errno));
return;
}
pthread_t id;
retcode = pthread_create(&id, &attr, ThreadRoute, (void *)this);
if(retcode != 0)
{
pthread_mutex_unlock(&m_startMutex);
nDebugLog(LOG_PRIORITY_ERROR, "pthread_create failed:%s!",strerror(errno));
return;
}
m_threadId = id;
pthread_attr_destroy(&attr);
m_bIsRunning = true;
}
pthread_mutex_unlock(&m_startMutex);
}
void TimerThread::Close()
{
m_bClosed = true;
pthread_mutex_lock(&m_mutex);
pthread_cond_signal(&m_cond);
pthread_mutex_unlock(&m_mutex);
pthread_join(m_threadId, NULL);
}
void TimerThread::CheckTimeOut(unsigned int elapse, std::list<TimerInfo> &timerList, int& minWaitTime)
{
int tmpWait = 0;
minWaitTime = 0;
pthread_mutex_lock(&m_mutex);
if (!m_timers.empty())
{
std::map<unsigned int, TimerInfo>::iterator it = m_timers.begin();
while (it != m_timers.end())
{
it->second.outTime += elapse;
tmpWait = it->second.outTime - int(it->second.elapse);
if (tmpWait >= 0)
{
timerList.push_back(it->second);
if (it->second.persistent)
{
it->second.outTime = 0;
++it;
}
else
{
m_timers.erase(it++);
}
}
else
{
tmpWait = tmpWait * -1;
if (minWaitTime == 0)
{
minWaitTime = tmpWait;
}
else if (minWaitTime > tmpWait)
{
minWaitTime = tmpWait;
}
++it;
}
}
}
else
{
pthread_cond_wait(&m_cond, &m_mutex);
}
pthread_mutex_unlock(&m_mutex);
}
unsigned int TimerThread::RegisterTimer(unsigned int initialDelay,unsigned int elapse, TimerHandler *pHandler, void * pOtherArg, bool persistent)
{
TimerInfo info;
info.elapse = elapse;
info.outTime = 0-initialDelay;
info.pTimerHandler = pHandler;
info.persistent = persistent;
info.pOtherArg = pOtherArg;
pthread_mutex_lock(&m_mutex);
info.id = GetNextTimerID();
m_timers[info.id] = info;
pthread_cond_signal(&m_cond);
pthread_mutex_unlock(&m_mutex);
return info.id;
}
bool TimerThread::UnRegisterTimer(unsigned int timerId)
{
bool result = false;
pthread_mutex_lock(&m_mutex);
std::map<unsigned int, TimerInfo>::iterator it = m_timers.find(timerId);
if (it != m_timers.end())
{
m_timers.erase(it);
result = true;
}
pthread_mutex_unlock(&m_mutex);
return result;
}
bool TimerThread::ResetTimer(unsigned int timerId)
{
bool result = false;
pthread_mutex_lock(&m_mutex);
std::map<unsigned int, TimerInfo>::iterator it = m_timers.find(timerId);
if (it != m_timers.end())
{
if (it->second.persistent)
{
it->second.outTime = it->second.elapse;
}
else
{
it->second.outTime = 0;
}
result = true;
}
pthread_mutex_unlock(&m_mutex);
return result;
}
unsigned int TimerThread::GetNextTimerID()
{
if (s_nextTimerID > 10000000)
{
s_nextTimerID = 0;
}
else
{
++s_nextTimerID;
}
return s_nextTimerID;
}
定时器SDK的更多相关文章
- 11-ESP8266 SDK开发基础入门篇--软硬件定时器
https://www.cnblogs.com/yangfengwu/p/11094009.html 定时器有两种,软件定时器和硬件定时器 软件定时器就是靠里面的任务延时实现的,,这样的定时器其实延时 ...
- 项目总结[2]_svg+ajax+webservice+pSpace sdk实现实时数据的web展示
1.使用svg实现组态画面和动态数据展示 通过js的定时器调用webservice方法获取数据后更新节点数据 /// <summary>启动定时刷新</summary> fun ...
- [nRF51822] 3、 新年也来个总结——图解nRF51 SDK中的Button handling library和FIFO library
:本篇是我翻译并加入自己理解的nRF51 SDK中按钮相关操作的库和先进先出队列库.虽然是nRF51的SDK,但是通过此文你将更多地了解到在BSP(板级支持)上层嵌入式程序或OS的构建方法. 1.按钮 ...
- android 定时器AlarmManager
1.android中通常是使用AlarmManager来定时启动一个单次或重复多次操作的.具体的说就是我们通过AlarmManager设定一个时间和注册一个intent到系统中,然后在该时间到来时,系 ...
- Android中直播视频技术探究之---采集摄像头Camera视频源数据进行推流(采用金山云SDK)
一.前言 在之前已经详细介绍了Android中的一种视频数据源:Camera,不了解的同学可以点击进入:Android中Camera使用详解 ,在这篇文章中我们介绍了如何采集摄像头的每一帧数据,然后进 ...
- android 定时器的使用
1.android中通常是使用AlarmManager来定时启动一个单次或重复多次操作的.具体的说就是我们通过AlarmManager设定一个时间和注册一个intent到系统中,然后在该时间到来时,系 ...
- Android之AlarmManager(全局定时器/闹钟)指定时长或以周期形式执行某项操作
1.AlarmManager,顾名思义,就是“提醒”,是Android中常用的一种系统级别的提示服务,可以实现从指定时间开始,以一个固定的间隔时间执行某项操作,所以常常与广播(Broadcast)连用 ...
- 基于百度定位SDK的定位服务的实现
转载请标明出处:http://blog.csdn.net/android_ls/article/details/10179013 一.定位模块的需求:我们想知道使用我们应用的用户的大概位置,每隔五分钟 ...
- ArcGIS Runtime SDK for Android开发之调用GP服务(异步调用)
一.背景说明 通过调用GP服务,Android客户端也能实现专业的.复杂的GIS分析处理功能,从而增加应用的实用价值. ArcGIS Server发布的GP服务,分为同步和异步两种类型,一般执行步骤较 ...
随机推荐
- POJ 2553 The Bottom of a Graph(强连通分量)
POJ 2553 The Bottom of a Graph 题目链接 题意:给定一个有向图,求出度为0的强连通分量 思路:缩点搞就可以 代码: #include <cstdio> #in ...
- Android开机键失灵启动手机的解决的方法
问题描写叙述 Android手机的关机键损坏,无法开机. 解决方法 将手机通过USB线链接电脑,进入命令行.找到adb命令所在文件夹.执行例如以下命令: adb reboot 注意:用这样的方法的前提 ...
- Element UI Form 每行显示多列,即多个 el-form-item
Element UI Form组件使用问题. 每个 el-form-item 都会独占一行. 对于输入项很多的管理app, 能否在每个form中, 每行显示 2 个或者多个 el-form-item ...
- Java-Maven:Maven清单
ylbtech-Java-Maven:Maven清单 1.返回顶部 2.返回顶部 3.返回顶部 4.返回顶部 5.返回顶部 6.返回顶部 作者:ylbtech出处:http ...
- Eclipse 连接hsqldb数据库
初学Java,在接触数据库根本无从下手,不知如何将程序和数据库连接起来,今天做一个记录. 数据库是:hsqldb_1_8_0_5 附链接百度云盘 链接:https://pan.baidu.com/s/ ...
- ORACLE 11g 生产中高水位线(HWM)处理
数据库中表不断的insert,delete,update,导致表和索引出现碎片.这会导致HWM之前有很多的空闲空间,而oracle在做全表扫描的时候会读取HWM一下的所有块,这样会产生更多的IO,影响 ...
- Spark Scala语言学习系列之完成HelloWorld程序(三种方式)
三种方式完成HelloWorld程序 分别采用在REPL,命令行(scala脚本)和Eclipse下运行hello world. 一.Scala REPL. windows下安装好scala后,直接C ...
- Git Learning Part III - working remotely (Github)
help document of Github : https://help.github.com/ 1 upload 1.1 new update Initialize a repository ...
- iOS11关于隐藏导航栏后带有tableView界面出现,下移问题
//解决iOS11关于隐藏导航栏后带有scrollView界面出现,下移问题 if (@available(iOS 11.0, *)) { self.tableView.contentInsetAdj ...
- 利用Axis2默认口令安全漏洞入侵WebService网站
近期,在黑吧安全网上关注了几则利用Axis2默认口令进行渗透测试的案例,大家的渗透思路基本一致,利用的技术工具也大致相同,我在总结这几则案例的基础之上进行了技术思路的拓展.黑吧安全网Axis2默认口令 ...