基于升序定时器的时间链表

李邦柱

[email protected]

1. 定时器简介

定时器通常包含至少两个成员:一个超时时间(通常采用相对时间或者超时时间)和一个超时时间到达后的一个回调函数。有时候还可能包含回调函数被执行时需要传入的参数,以及是否重新启动定时器,更改定时器的超时时间等。如果使用链表作为容器来串联所有的定时器,则每个定时器还要包含指向下一个定时器的指针成员。进一步,如果链表是双向的,则每个定时器还需要包含指向前一个定时器的指针成员。

2. 升序定时器链表的实现

#ifndef LST_TIMER
#define LST_TIMER
#include<time.h>
#define BUFFER_SIZE 64
class Timer;/*向前声明*/*/

/*用户数据结构,包含ip,端口,文件描述符,读缓存,以及定时器*/
struct client_data
{
  char ip[BUFFER_SIZE];
  int port;
  int sockfd;
  char buf[BUFFER_SIZE];
  Timer *timer;

};

/*定时器类*/
class Timer
{
 public:
	Timer():prev(NULL),next(NULL){}
 public:
    time_t expire;/*任务的超时时间,此处使用绝对时间*/
	client_data* user_data;
	void (*cb_func)(client_data*);/*任务回调函数*/
	Timer* prev;/*指向前一个定时器*/
	Timer* next;/*指向后一个定时器*/
	void* arg;  /*可根据需要进行扩展使用*/

};

/*定时器链表,它是一个升序,双向链表,且带有头节点和尾节点*/
class sort_timer_lst
{
public:
	sort_timer_lst():head(NULL),tail(NULL){}
	~sort_timer_lst()/*链表被销毁的时候,删除所有的定时器*/
	{
		Timer* tmp =head;
		while(tmp)
		{
			head=tmp->next;
			delete tmp;
			tmp =head;

		}
	}
	void add_timer(Timer* timer);/*将目标定时器添加到链表中*/
	bool find_timer(Timer* timer);/*查找目标定时器*/
	void del_timer(Timer* timer);/*删除目标定时器*/
	void adjust_timer(Timer* timer);/*当某个定时任务发生变化时,调整对应的定时器在链表的位置,此函数之考的向后调整*/
	void tick();
private:
    void add_timer(Timer* timer,Timer* head);
	private:
	Timer* head;
	Timer* tail;

};

#endif

lst_timer.cpp

#include"lst_timer.h"

void sort_timer_lst::add_timer(Timer* timer)
{
	if(!timer) return;
		if(!head)
		{
			head= tail =timer;
			return ;
		}

		if(timer->expire < head->expire)
		{
		  timer->next = head;
		  head ->prev = timer;
		  head = timer;
		  return ;

		}

		add_timer(timer,head);

}

bool sort_timer_lst:: find_timer(Timer* timer)
{

	Timer* tmp = head;
	while(tmp)
	{
		if(strcmp(tmp->user_data->stb_id , timer->user_data->stb_id)==0)
		{

				return true;

		}

		       tmp = tmp->next;

	}
		if(!tmp)
		return false;

}

void sort_timer_lst::adjust_timer(Timer*timer)
{
	if(!timer)
		return;

	Timer*tmp = timer->next;
	if(!tmp||timer->expire<tmp->expire)
		return;

	if(timer==head)
	{
		head = head->next;
		head->prev =NULL;
		timer->next = NULL;
		add_timer(timer,head);

	}
	else
	{
		timer ->prev->next = timer ->next;
		timer ->next->prev = timer->prev;
		add_timer(timer,timer->next);

	}

}

void sort_timer_lst::del_timer(Timer* timer)
{

	if(!timer)
		return;
	/*下面条件成立,表示只有一个定时器,即目标定时器*/
	if((timer ==head)&&(timer ==tail))
	{
		delete timer;
		head = NULL;
		tail = NULL;
		return ;

	}
	/*如果链表至少有两个定时器,且目标定时器恰好是头结点*/
	if(timer == head)
	{
		head =head->next;
		head->prev=NULL;
		delete timer;
		return;

	}
	/*如果链表至少有两个定时器,目标定时器恰好是尾节点*/
	if(timer ==tail)
	{
		tail = tail ->prev;
		tail ->next =NULL;
		delete timer;
		return;

	}
	/*目标定时器如果位于链表头尾之间,则把它前后的定时器串联起来,然后删除目标定时器*/
	timer->prev ->next =timer ->next;
	timer->next->prev = timer ->prev ;
	delete timer;

}

/*主要通过此函数不断检测时候有定时器超时*/
void sort_timer_lst::tick()
{

	if(!head ) return;

	time_t cur = time(NULL);

	Timer* tmp = head;

	while(tmp)
	{
		if(cur<tmp->expire)
		break;

		tmp->cb_func(tmp->user_data);/*执行定时器回调函数*/

		head=tmp->next;
		if(head)
		head->prev = NULL;

		delete tmp;
		tmp = head;

	}

}

void sort_timer_lst:: add_timer(Timer* timer,Timer* head)
{

	Timer* prev = head;
	Timer* tmp = prev->next;

	while(tmp)
	{
		if(timer->expire<tmp->expire)
		{
			prev->next =timer ;
			timer->next = tmp;
			tmp ->prev = timer;
			timer ->prev = prev;
			break;

		}

		prev = tmp;
		tmp =tmp->next;

	}

	if(!tmp)
	{
		prev->next = timer;
		timer->prev = prev;
		timer->next =NULL;
		tail = timer;

	}

}

3. 性能分析

Sort_timer_lst是一个升序链表,其核心函数是tick,相当于一个脉搏,让它每隔一段时间就执行一次,以检测并处理到期的任务。判定定时任务到期的依据是定时的expire值小于或者等于当前时间。从执行效率上看添加定时器的任务的时间复杂度为O(n),删除定时器的时间复杂度为O(1),执行任务的时间复杂度是O(1).

4. 其他高性能定时器

基于排序链表的定时器存在一个效率的问题,添加定时器的效率偏低,因此可以使用时间轮或者时间堆来解决这个问题。有兴趣的朋友可以学习下时间轮和时间堆。

5. 更多内容,请前往个人文库

http://wenku.baidu.com/p/helpylee

基于升序定时器的时间链表,布布扣,bubuko.com

时间: 2024-08-16 10:30:37

基于升序定时器的时间链表的相关文章

Linux内核——定时器和时间管理

定时器和时间管理 系统定时器是一种可编程硬件芯片.它能以固定频率产生中断.该中断就是所谓的定时器中断.它所相应的中断处理程序负责更新系统时间,还负责执行须要周期性执行的任务. 系统定时器和时钟中断处理程序是Linux系统内核管理机制中的中枢. 另外一个关注的焦点是动态定时器--一种用来推迟运行程序的工具. 比方说.假设软驱马达在一定时间内都未活动,那么软盘驱动程序会使用动态定时器关闭软驱马达. 内核能够动态创建或销毁动态定时器. 内核中的时间观念 内核在硬件的帮助下计算和管理时间. 硬件为内核提

向下之旅(十四):定时器和时间管理

相对于事件驱动而言,内核中有大量的函数都是基于时间驱动的.有些函数是周期执行的,有些操作是需要等待一个相对的时间后才运行.除了上述两类函数需要内核提供时间外,内核还必须管理系统的运行时间以及当前日期和时间. 其中相对时间和绝对时间是不同的,若某个事件在5秒后被调度执行,那么系统所需要的是——相对时间(相对现在起5秒).如果涉及到日期和时间,内核不但要计算流逝的时间还要计算绝对时间. 周期性产生的事件和推迟执行的时间之间的差别:前者比如每10毫秒一次——都是由系统定时器驱动的.系统定时器是一种可编

Linux之定时器与时间管理 【转】

转自:http://blog.chinaunix.net/uid-23228758-id-154820.html 定时器与时间管理: 1.节拍率——HZ:在alpha体系结构上1024,而在其它平台上,都为10数量级倍.在嵌入式ARM上为100(2.6内核).这个值的意义是什么呢,也就是在ARM平台上时钟中断100次,为一秒.一般的情况下编程者不要改变这个值,因为内核编很多代码都是有时间要求的,而且内核编写都在很多地方都做了相应的优化与折衷处理,改变HZ的值会对系统的性能有很大的影响. 2.ji

基于数组实现的单链表(兼具Boost单元测试)

对于单链表,我们大多时候会用指针来实现(可参考基于指针实现的单链表).现在我们就来看看怎么用数组来实现单链表. 1. 定义单链表中结点的数据结构 1 typedef int ElementType; 2 class NodeType 3 { 4 public: 5 ElementType data; 6 int next; 7 }; 该结点包括了两个元素,其一是数据,另一个是指向下一个结点的"指针"(在这篇文章中实际上是指用于实现单链表的数组的下标.)  2. 定义一个的数组 1 co

Spring如何动态地设置定时器的时间

本来想采用注解的方式,读配置文件来达到动态设置cron表达式,一直没能成功,改用XML方法配置 1.在spring.xml配置要执行的定时器的类,这里为com.ndasec.web.core.quartz下的MessageTimer <bean id="messageTask" class="com.ndasec.web.core.quartz.MessageTimer"></bean>  2.设置要执行的该类中的哪个方法,ref为上面bea

用定时器中断,单片机中断处理时间大于定时器定时时间会怎样?

如果是不同的中断类型是可以根据优先级嵌套,如果是同一中断类型(如题), 有三种结果:1.马上进入新的中断处理(中断嵌套) 2.等待中断处理完再进入新的中断处理 3.出错. 单片机中断处理时间大于定时器定时时间,在下次中断时间到时,因为中断是同一类型.同一优先级,所以不会马上进入新的中断处理. 而是在本次中断处理结束后,单片机又马上进入新的定时器中断函数,主函数中的语句可能会没有机会运行下去,会影响后面中断的实时性.所以答案为2. 如果为了避免中断嵌套(同一优先级不会发生),在中断处理中人为的在进

将秒数转换为基于00:00的时间

/** * 将秒数转换为基于00:00的时间 * 如541=9*60+1,表示09:01 * @param minutes * @return */ public static String getTimeByMinutes(int minutes){ //处理小时 int hour = minutes / 60; String hourTime = ""; if(hour >= 0 && hour < 10){ hourTime = "0&quo

如何在网页中设置一个定时器计算时间?

写一个简单的计数js代码 首先先写一个div,用于存放计数器,并且通过改变样式可以改变计数器的样子 <body> <div id="le"></div> </body> <style type="text/css"> #le{ position: fixed; right: 100px; top: 200px; width: 250px; height: 200px; background-color: #

基于无头节点的单链表的升序冒泡排序(C++实现)

由于基础代码的特殊(链表为无头链表),以下冒泡排序算法采用两种方式进行排序.首先对首节点往后的所有节点进行排序,这里使用的是对其索引顺序改变的方法.然后对首节点进行排序,只需要一次循环即可,这里使用的是对节点中的数值进行交换的方法. 1 #include <iostream> 2 using namespace std ; 3 4 #define ERROR -1 5 #define CORRECT 1 6 7 //定义 8 struct LNode { 9 int data ; 10 LNo