定时器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服务,分为同步和异步两种类型,一般执行步骤较 ...
随机推荐
- 线程同步、死锁和通信——Java多线程(二)
一.多线程同步 上一篇随笔中,我曾遇到对多线程程序的多次运行结果不一致的情况,这主要是因为没有对这些线程在访问临界资源做必要的控制,而接下来就用线程的同步来解决这个问题. 1.同步代码块 class ...
- udev的使用-minicom没有权限打开串口,更改 ttyUSB0 的权限
udev的使用-minicom没有权限打开串口,更改 ttyUSB0 的权限 使用minicom打开串口会提示没有权限,必需要用 sudo,怎样更改串口设备的权限能够让普通用户读写呢? 事实上仅仅要更 ...
- Running the app on your device
So far, you've run the app on the Simulator. That's nice and all but probably notwhy you're learning ...
- h5-8 canvas
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Truck History --hdoj
Truck History Time Limit : 4000/2000ms (Java/Other) Memory Limit : 131072/65536K (Java/Other) Tota ...
- Mysql数据库性能
Mysql数据库设计规范 https://www.cnblogs.com/Luke-Me/p/8994432.html 我们在项目一开始的设计中,就要忙着考虑数据库的设计,表.字段.索引.sql等等, ...
- IOS-UITextField-改变光标颜色
方法1: [[UITextField appearance] setTintColor:[UIColor blackColor]]; 这种方法将影响所有TextField. 方法2: textFiel ...
- (转载)更新到Retrofit2的一些技巧
更新到Retrofit2的一些技巧 作者 小武站台 关注 2016.02.22 22:13* 字数 1348 阅读 1621评论 0喜欢 5赞赏 1 原文链接:Tips on updating to ...
- H5 微信公众号 监听返回事件
/*-----监听返回事件-----*/ function pushHistory(returnUrl,currentUrl,currentTitle) { window.addEventListen ...
- 在YII2中使用redis
一.安装YII2的redis扩展 composer require --prefer-dist yiisoft/yii2-redis 二. 配置basic/config/web.php 在compon ...