定时器是一切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的更多相关文章

  1. 11-ESP8266 SDK开发基础入门篇--软硬件定时器

    https://www.cnblogs.com/yangfengwu/p/11094009.html 定时器有两种,软件定时器和硬件定时器 软件定时器就是靠里面的任务延时实现的,,这样的定时器其实延时 ...

  2. 项目总结[2]_svg+ajax+webservice+pSpace sdk实现实时数据的web展示

    1.使用svg实现组态画面和动态数据展示 通过js的定时器调用webservice方法获取数据后更新节点数据 /// <summary>启动定时刷新</summary> fun ...

  3. [nRF51822] 3、 新年也来个总结——图解nRF51 SDK中的Button handling library和FIFO library

    :本篇是我翻译并加入自己理解的nRF51 SDK中按钮相关操作的库和先进先出队列库.虽然是nRF51的SDK,但是通过此文你将更多地了解到在BSP(板级支持)上层嵌入式程序或OS的构建方法. 1.按钮 ...

  4. android 定时器AlarmManager

    1.android中通常是使用AlarmManager来定时启动一个单次或重复多次操作的.具体的说就是我们通过AlarmManager设定一个时间和注册一个intent到系统中,然后在该时间到来时,系 ...

  5. Android中直播视频技术探究之---采集摄像头Camera视频源数据进行推流(采用金山云SDK)

    一.前言 在之前已经详细介绍了Android中的一种视频数据源:Camera,不了解的同学可以点击进入:Android中Camera使用详解 ,在这篇文章中我们介绍了如何采集摄像头的每一帧数据,然后进 ...

  6. android 定时器的使用

    1.android中通常是使用AlarmManager来定时启动一个单次或重复多次操作的.具体的说就是我们通过AlarmManager设定一个时间和注册一个intent到系统中,然后在该时间到来时,系 ...

  7. Android之AlarmManager(全局定时器/闹钟)指定时长或以周期形式执行某项操作

    1.AlarmManager,顾名思义,就是“提醒”,是Android中常用的一种系统级别的提示服务,可以实现从指定时间开始,以一个固定的间隔时间执行某项操作,所以常常与广播(Broadcast)连用 ...

  8. 基于百度定位SDK的定位服务的实现

    转载请标明出处:http://blog.csdn.net/android_ls/article/details/10179013 一.定位模块的需求:我们想知道使用我们应用的用户的大概位置,每隔五分钟 ...

  9. ArcGIS Runtime SDK for Android开发之调用GP服务(异步调用)

    一.背景说明 通过调用GP服务,Android客户端也能实现专业的.复杂的GIS分析处理功能,从而增加应用的实用价值. ArcGIS Server发布的GP服务,分为同步和异步两种类型,一般执行步骤较 ...

随机推荐

  1. ubuntu14.04 安装LNMP

    新书上市<深入解析Android 5.0系统> 通常我们使用centos来组建LNMP,可是我们开发时多使用ubuntu的桌面版本号来调试,以下将具体介绍怎样在ubuntu上安装一套LNM ...

  2. Linux开发环境搭建与使用——Linux必备软件之Samba

    假如我们是在ubuntu环境上做对应的开发.有的时候,我们须要把我们写的程序共享给别人,或者,自己拷贝出来备份一份.我们习惯用U盘拷贝,假设须要频繁拷贝的话,这样会不太方便.这里给大家介绍一种更好的方 ...

  3. 2016.04.07,英语,《Vocabulary Builder》Unit 11

    cant, from the Latin verbs canere and cantare, meaning 'sing'. by way of French, add an h to the roo ...

  4. canvas的自动画图

    <!DOCTYPE HTML><html><body> <canvas id="myCanvas" width="200&quo ...

  5. 认识React框架

    在大厂面试的时候被问会不会React框架几乎是必须的,可见React框架在现在前端市场的份额.所以说学习React框架的必要性. react框架起源于Facebook的内部项目,因为对市场上的Java ...

  6. 如何用ajax写分页查询(以留言信息为例)-----2017-05-17

    要写分页,首先你得清楚,一页你想显示多少条信息?如何计算总共显示的页数? 先说一下思路: (1)从数据库读取数据,以chenai表为例,读取所有留言信息.并能够实现输入发送者,可以查询该发送者的留言总 ...

  7. CentOS6.5下编译R源码并安装Spark R

    不多说,直接上干货! 为了使用SparkR,决定要在Spark所在的Linux上装上R,结果血泪篇了.主要原因是公司内部的虚机,无法连外网,所以网上很多的直接rpm或者yum的方法都没用,需要自己编译 ...

  8. Solr.NET快速入门(五)【聚合统计,分组查询】

    聚合统计 属性 说明 Min 最小值 Max 最大值 Sum 总和 Count 记录数,也就是多少行记录 Missing 结果集中,有多少条记录是空值 SumOfSquares 平方和(x1^2 + ...

  9. 深度讲解智能硬件手机APP开发流程

    常州做APP开发公司紫竹云科技分析,智能硬件产品的软件开发,除了APP和后台之外还有一个固件端的开发,由于固件是要运行产品上的,不过此时的硬件也是刚开始进行研发,所以是无法提供硬件来运行固件的.因此在 ...

  10. Kettle通用数据贴源作业设计

    本设计基于以下需求提出 1. 快速接入数据源表(贴源/落地) 2. 无须给单独表开发转换/作业 3. 动态生成数据源连接, 表字段等信息(预先保存在数据仓库中) 本设计所需条件 1. 数据源为关系型数 ...