定时器是一切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. python为在线漫画站点自制非官方API(未完待续)

    接下来将记录我一步一步写一个非官方API的过程,由于一些条件的约束,最后的成品可能非常粗暴简陋 如今介绍要准备的全部工具: 系统:ubuntu 14.04 语言:python 2.7 须要自行安装的库 ...

  2. 基于aspectj的aop的操作

    1.引入相关的jar包 2.建两个类 public class Book { public void add(){ System.out.println("add-----------&qu ...

  3. Cracking the Coding Interview 6.2

    There is an 8*8 chess board in which two diagnolly opposite corners have been cut off. You are given ...

  4. Python基础教程思维导图笔记

    说明:直接查看图片可能不太清楚,用浏览器打开后,按住 Ctrl ,网上滚动鼠标放大浏览器页面,可以看清楚图片

  5. Super超级ERP系统---(10)订单打包

    订单拣货完成后,需要把订单装箱打包,并打印客户地址信息.订单打包的操作流程先是扫描订单号,然后扫描商品条码.  1.订单打包 打印包装箱面单 2.订单发货 订单打包完成后就等待发货,快递公司来拉货的时 ...

  6. Gitlab 灾备措施

    Gitlab创建备份 使用Gitlab一键安装包安装Gitlab非常简单,同样的备份恢复与迁移也非常简单.使用一条命令即可创建完整的Gitlab备份: gitlab-rake    gitlab:ba ...

  7. 第4章 部署模式 Deployment Plan(部署规划)

    已开发了基于组件的应用程序,该应用程序在逻辑上构造为多层结构,如 Three-Layered Services Application. 中所述.您希望将它分布到一组在物理上为多级结构的服务器上,如 ...

  8. python课程设计笔记(四)整数、浮点数与字符串 time库

    整数类型(范围无限制) 十进制1 -1 二进制0b1 -0b1 八进制0o1 -0o1 十六进制0x1 -0x1 浮点类型(范围有限制但可忽略) 运算存在不确定尾数 :0.1+0.2!=0.3 原因: ...

  9. 在YII2中使用memcached

    一.在本地安装Memcached服务器和安装memcached扩展 http://www.cnblogs.com/songziqing/p/5896742.html http://www.cnblog ...

  10. vue-cli 结构

    . |-- build                            // 项目构建(webpack)相关代码 |   |-- build.js                     // ...