C++实现的简单的定时器

已经好几天没有写博客了。
这几天都在看定时器,想搞清楚他的原理,想知道他到底是怎么用的。无奈没有一篇能够比较系统地告诉我定时器是干什么的,怎么用的,导致项目长时间停滞。
在看了几篇博客之后,根据我自己的理解,实现了一个简单的定时器,其中有参考其他的博文的写法,好在我现在实现了一个看起来能用的定时器。

定时器的应用场景

场景一:keep alive保活机制

成千上万个客户端去连接一台聊天服务器,那么就会存在成千上万个tcp连接。但是这些tcp连接是每时每刻都保持发包收包的活跃状态吗?不是!

某些tcp连接上,可能建立之后,在一天之内就没再发包/收包过,为了把有限的系统资源分配给更活跃的用户使用,我们应该设计一种方案来踢掉空闲连接。

场景二:游戏中,指定时间(或间隔时间)执行某种特定操作

  • 每日/每周/每月,特定时间执行一次操作

  • 循环执行的定时器,比如每隔一分钟刷新一次野怪

  • 只执行一次的定时器,在60秒后定时器超期,执行操作A

各种定时器性能比较

实现方式 StartTimer StopTimer PerTickBookkeeping
基于排序的链表 O(n) O(1) O(1)
基于最小堆 O(logn) O(1) O(1)
基于时间轮 O(1) O(1) O(1)

具体实现

这里采用了最小堆实现
Timer_mng.h

#ifndef __TIMER_MNG_
#define __TIMER_MNG_

#define ull unsigned long long 
#define __INF__ 1e18

using namespace std;

enum t_type {ONCE,CIRCLE};

class Timer_mng;
class Timer;

struct Heap_entry{		//堆条目
	unsigned long long time;
	Timer *timer;
};
struct Timer{
	t_type ttype;		//任务类型,一次还是循环
	void *(*run)(void *args);	//回调函数
	void *arg;					//会调函数参数
	ull itvl;					//时间片长度(ms)
	ull expires;				//到期时间
	int heapIndex;				//在堆中的下标
	Timer();					//初始化
	void Start(void *(*run)(void *args),void *arg,ull itvl, t_type ttype);
	void OnTimer();				//无剩余时间		
};
struct Timer_mng{
	vector<Heap_entry*>heap;		//堆
	~Timer_mng();					//析构函数
	void DetectTimers();			//检测是否超时
	void AddTimer(Timer* timer);	//向堆中添加一个定时器
	void RemoveTimer(Timer* timer);	//移除定时器
	void UpHeap(int idx);			//堆操作,向上更新
	void DownHeap(int idx);			//堆操作,向下更新
	void SwapHeap(int idx1, int idx2);	//更换堆中的两个元素
};

ull Get_now();			//得到当前时间(ms)

#endif

Timer_mng.cpp

#include<cstdio>
#include<cstring>
#include<sys/time.h>
#include<vector>
#include"Timer_mng.h"
using namespace std;
//Timer

Timer::Timer(){
    heapIndex=-1;
}
void Timer::Start(void *(*run)(void *args),void *arg,ull itvl, t_type ttype){
    itvl=itvl;
    this->run=run,this->arg=arg;
    ttype=ttype;
    printf("Now :%llu\n",Get_now());
    expires=itvl+Get_now();
}
 
void Timer::OnTimer(){
    heapIndex=-1;
   // printf("%d\n",*(int*)arg);
    this->run(this->arg);
}
 
//Timer_mng

Timer_mng::~Timer_mng(){
    heap.clear();
}

void Timer_mng::AddTimer(Timer* timer){  
    timer->heapIndex=heap.size();
    Heap_entry *entry=(Heap_entry*)malloc(sizeof(Heap_entry));
    entry->time=timer->expires;
    entry->timer=timer;
//    timer->run(timer->arg);
    heap.push_back(entry);
    UpHeap(heap.size()-1);
 //   free(entry);
}
 
void Timer_mng::RemoveTimer(Timer* timer){
    int idx=timer->heapIndex;
    if (!heap.empty()&&idx<heap.size()){
        if(idx==heap.size()-1){
            heap.pop_back();
        }
        else{
            SwapHeap(idx,heap.size()-1);
            heap.pop_back();
            int parent=(idx-1)/2;  //堆中父节点编号
            if(idx>0&&heap[idx]->time<heap[parent]->time)
                UpHeap(idx);
            else
                DownHeap(idx);
        }
    }
}
 
void Timer_mng::DetectTimers(){
    printf("----%lu\n",heap.size());
    while(!heap.empty()){
        ull now=Get_now();
        if(heap[0]->time<=now){
            Timer *timer=(Timer *)malloc(sizeof(Timer));
            timer=heap[0]->timer;
      //      printf("%d\n",*(int *)heap[0]->timer->arg);
            if(heap[0]->timer->run==NULL||heap[0]->timer->arg==NULL){
                perror("ERROR!");
                return;
            }

           // heap[0]->timer->run(heap[0]->timer->arg);
            RemoveTimer(timer);
            if(timer->ttype==CIRCLE){
                timer->expires=timer->itvl+Get_now();
                this->AddTimer(timer);
            }
            timer->OnTimer();
           // printf("xxx\n");
        }
    }
}
 
void Timer_mng::UpHeap(int idx){
    int parent=(idx-1)/2;
    while(idx>0&&heap[idx]->time<heap[parent]->time){
        SwapHeap(idx,parent);
        idx=parent;
        parent=(idx-1)/2;
    }
}
 
void Timer_mng::DownHeap(int idx){
    int child=idx*2+1;
    while(child<heap.size()){
        int minChild=(child+1==heap.size()||heap[child]->time<heap[child+1]->time)
            ?child:child+1;
        if(heap[idx]->time<heap[minChild]->time)
            break;
        SwapHeap(idx,minChild);
        idx=minChild;
        child=idx*2+1;
    }
}
 
void Timer_mng::SwapHeap(int idx1, int idx2){
    Heap_entry *tmp=heap[idx1];
    heap[idx1]=heap[idx2];
    heap[idx2]=tmp;
    heap[idx1]->timer->heapIndex=idx1;
    heap[idx2]->timer->heapIndex=idx2;
}

ull Get_now(){
    #ifdef _MSC_VER
        _timeb timebuffer;
        _ftime(&timebuffer);
        ull ret=timebuffer.time;
        ret=ret*1000+timebuffer.millitm;
        return ret;
    #else
        timeval tv;         
        ::gettimeofday(&tv,0);
        ull ret=tv.tv_sec;
        return ret*1000+tv.tv_usec/1000;
    #endif
}
// init()

函数调用关系图

AddTimer()---->UpHeap()
      
DetectTimers()----->RemoveTimer()--->UpHeap()------|
             |             |    |                  |
             |             |    --->DownHeap()-----|
             |             |                       |
             |             ---------------------->SwapHeap()
             |
             --->OnTimer()(AddTimer())

一个简单的例子

#include<stdio.h>
#include<iostream>
#include<vector>
#include"Timer_mng.h"
using namespace std;

#define LONGTIME 8000
// 定时事件回调函数
void *onTime(void *arg){
	int *id=(int *)arg;
    cout<<*id<<" Game Over!"<< endl;
    return nullptr;
}
 
int main(){
	// 初始化
    Timer_mng Mymng;
    for(int i=0;i<10;i++){
 		Timer *t=(Timer *)malloc(sizeof(Timer));   	
    	int *tmp=(int *)malloc(sizeof(int));
    	*tmp=i;
    	t->Start(onTime,tmp,LONGTIME,ONCE);
    	//t->run(t->arg);
    	Mymng.AddTimer(t);
    }
   // while(Mymng.heap.size())
 	Mymng.DetectTimers();
    return 0;
}

运行结果
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Monster_ixx/article/details/88651721