定时器是一切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. 线程同步、死锁和通信——Java多线程(二)

    一.多线程同步 上一篇随笔中,我曾遇到对多线程程序的多次运行结果不一致的情况,这主要是因为没有对这些线程在访问临界资源做必要的控制,而接下来就用线程的同步来解决这个问题. 1.同步代码块 class ...

  2. udev的使用-minicom没有权限打开串口,更改 ttyUSB0 的权限

    udev的使用-minicom没有权限打开串口,更改 ttyUSB0 的权限 使用minicom打开串口会提示没有权限,必需要用 sudo,怎样更改串口设备的权限能够让普通用户读写呢? 事实上仅仅要更 ...

  3. 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 ...

  4. h5-8 canvas

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  5. Truck History --hdoj

    Truck History Time Limit : 4000/2000ms (Java/Other)   Memory Limit : 131072/65536K (Java/Other) Tota ...

  6. Mysql数据库性能

    Mysql数据库设计规范 https://www.cnblogs.com/Luke-Me/p/8994432.html 我们在项目一开始的设计中,就要忙着考虑数据库的设计,表.字段.索引.sql等等, ...

  7. IOS-UITextField-改变光标颜色

    方法1: [[UITextField appearance] setTintColor:[UIColor blackColor]]; 这种方法将影响所有TextField. 方法2: textFiel ...

  8. (转载)更新到Retrofit2的一些技巧

    更新到Retrofit2的一些技巧 作者 小武站台 关注 2016.02.22 22:13* 字数 1348 阅读 1621评论 0喜欢 5赞赏 1 原文链接:Tips on updating to ...

  9. H5 微信公众号 监听返回事件

    /*-----监听返回事件-----*/ function pushHistory(returnUrl,currentUrl,currentTitle) { window.addEventListen ...

  10. 在YII2中使用redis

    一.安装YII2的redis扩展 composer require --prefer-dist yiisoft/yii2-redis 二. 配置basic/config/web.php 在compon ...