升序定时器的时间链表的完全实现

2023-11-14

                                   李邦柱

                                                       helpylee@126.com


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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

升序定时器的时间链表的完全实现 的相关文章

  • 【Logback】<logger>、<root>标签详解

    文章目录 背景 一
  • Java语言通过三种方法来实现队列

    队列 关于作者 作者介绍 博客主页 作者主页 简介 JAVA领域优质创作者 一名在校大三学生 在校期间参加各种省赛 国赛 斩获一系列荣誉 关注我 关注我学习资料 文档下载统统都有 每日定时更新文章 励志做一名JAVA资深程序猿 文章目录 队
  • 华为OD机试 - 生日礼物(Java)

    题目描述 小牛的孩子生日快要到了 他打算给孩子买蛋糕和小礼物 蛋糕和小礼物各买一个 他的预算不超过x元 蛋糕cake和小礼物gift都有多种价位的可供选择 请返回小牛共有多少种购买方案 输入描述 第一行表示cake的单价 以逗号分隔 第二行
  • LeetCode83: 删除排序链表中的重复元素

    给定一个已排序的链表的头 head 删除所有重复的元素 使每个元素只出现一次 返回 已排序的链表 示例 1 输入 head 1 1 2 输出 1 2 示例 2 输入 head 1 1 2 3 3 输出 1 2 3 提示 链表中节点数目在范围
  • 数据结构 严薇敏 顺序表的实现(增 删 改)及其使用方法详解

    时间复杂度 数据结构 时间复杂度和空间复杂度 目录 1 线性表 2 顺序表 2 1概念及结构 2 2 接口实现 SeqList h SeqList c 2 2 1初始化链表以及销毁链表的实现 初始化顺序表 销毁顺序表 2 2 2查找元素前驱
  • C++中的.和->

    C 中的 和 gt 1 C 中的点 的应用 如果是一个对象或者引用去调用成员变量或者成员函数函数的话 会使用到点 include
  • 【Java 数据结构】单链表与OJ题

    篮球哥温馨提示 编程的同时不要忘记锻炼哦 暮色降临 冲一杯咖啡 目录 1 什么是链表 2 实现一个单向非循环链表 2 1 实现前的约定 2 2 addFirst 方法 2 3 addList 方法 2 4 addIndex 方法 2 5 c
  • LeetCode 142. 环形链表 II

    题目链接 https leetcode cn problems linked list cycle ii 思路如下 用两个指针 fast slow 同时从起点开始走 fast 每次走两步 slow 每次走一步 如果过程中 fast 走到 n
  • 剑指 Offer 18. 删除链表的节点 -- 双指针

    0 题目描述 leetcode原题链接 剑指 Offer 18 删除链表的节点 1 双指针解法 删除值为 val 的节点分需为两步 定位节点 修改引用 定位节点 遍历链表 直到 head val val 时跳出 即可定位目标节点 修改引用
  • 95-34-030-Context-DefaultChannelHandlerContext

    文章目录 1 概述 2 继承体系 3 源码 1 概述 2 继承体系 3 源码 final class DefaultChannelHandlerContext
  • 2020.11.13 奇偶链表

    2020 11 13 奇偶链表 题目描述 给定一个单链表 把所有的奇数节点和偶数节点分别排在一起 请注意 这里的奇数节点和偶数节点指的是节点编号的奇偶性 而不是节点的值的奇偶性 请尝试使用原地算法完成 你的算法的空间复杂度应为 O 1 时间
  • 2-数据结构-线性表之顺序表的动态分配

    说明 由于原来顺序表的静态分配 浪费空间 且存在溢出现象 因此采取动态分配的方式 创建顺序表中的数组 跟C语言正常动态分配一样 需要直到扩充的大小 和数组指针即可 代码如下 看着多 其实原理差不多 主要知道哪些操作即可 无需了解具体代码 i
  • 讲解+可执行完整代码 C++单链表(2)查找、插入、删除元素

    目录 一 查找元素 代码部分 核心代码 完整代码 二 插入元素 核心思路 代码部分 核心代码 完整代码 编辑 三 删除元素 核心思路 代码部分 核心代码 完整代码 一 查找元素 此段代码仅实现查找元素的功能 代码部分 核心代码 node l
  • 数据结构之链表增删查改(最详细注释和最清晰思路,附完整代码)

    PZK学数据结构之链表 史上最详细思路和代码注释 完整代码我放在最后面了 可以直接跑 方便大家cv编程 文章目录 PZK学数据结构之链表 史上最详细思路和代码注释 完整代码我放在最后面了 可以直接跑 方便大家cv编程 前言 一 链表是什么
  • 华为OD机试真题-最长子字符串的长度(一)-2023年OD统一考试(C卷)

    题目描述 给你一个字符串 s 字符串s首尾相连成一个环形 请你在环中找出 o 字符出现了偶数次最长子字符串的长度 输入描述 输入是一串小写字母组成的字符串 输出描述 输出是一个整数 补充说明 1 lt s length lt 5 x 10
  • 算法题-简单系列-03-判断链表中是否有环

    文章目录 1 题目 1 1 思路1 双指针 1 2 思路2 哈希表 1 题目 判断给定的链表中是否有环 如果有环则返回true 否则返回false 1 1 思路1 双指针 我们使用两个指针 fast 与 slow 它们起始都位于链表的头部
  • 华为OD机试 C++【最大载货量】

    描述 在火车站旁的货运站 小明负责调度2K辆中转车 其中K辆用于干货 K辆用于湿货 每批到站的货物来自不同的供货商 需要按照顺序装入中转车 注意 一个供货商的货物只能装在一辆车上 不能分开 但是 一辆车可以放多个供货商的货物 问题是 要让所
  • 《LeetCode力扣练习》代码随想录——双指针法(反转链表---Java)

    LeetCode力扣练习 代码随想录 双指针法 反转链表 Java 刷题思路来源于 代码随想录 206 反转链表 双指针 Definition for singly linked list public class ListNode int
  • 《LeetCode力扣练习》代码随想录——双指针法(反转链表---Java)

    LeetCode力扣练习 代码随想录 双指针法 反转链表 Java 刷题思路来源于 代码随想录 206 反转链表 双指针 Definition for singly linked list public class ListNode int
  • 单向不带头链表的使用

    单向不带头链表的使用 链表的创建 typedef struct LNode SLDataType data struct LNode next LNode LinkList 按位查找 LNode GetElem LinkList L int

随机推荐

  • 【java】for和foreach的区别

    一 概述 普通for循环在遍历集合时使用下标来定位集合中的元素 java在JDK1 5开始支持foreach循环 foreach在一定程度上简化了对集合的遍历 但某些情况下 foreach是不能完全代替for循环的 限制场景 1 forea
  • IC卡、ID卡、CPU卡、RFID和NFC的区别

    ID卡 ID卡是早期的电子标签 只有一个ID号 不可以存储任何数据 故叫ID卡 ID卡没有算法 不可写入数据 其ID出厂一次性写入 应用人员只可读出卡号加以利用 ID卡容易复制 安全性较低 应用 主要应用在门禁系统 企业工牌 安全性 ID
  • 【Photon Voice】介绍

    入门 Photon Voice 2是Photon Voice的后续版本 它带来了以下功能 改进了API和更好的Unity组件 与PUN2兼容 灵活性 由于现在它与PUN2分离 它可以与Photon Realtime Photon Bolt
  • PacketTracer简单使用】

    进入软件后 我所用的版本是5 3 汉化过 看到如下界面 搭建网络拓扑 上图中的1 最大空白地方叫工作空间 搭建网络拓扑的地方 分逻辑和物理空间 2处的两个图标可以切换模式 图中的3 我们需要选取的网络设备名称 如路由器 接线器 4就是具体型
  • 【ORBSLAM2点线融合】线特征图模型构建

    在SLAM中 通常用BA Bundle Adjustment 来实现多个三维点和不同相机位姿的优化 本文描述如何建立基于线特征的图优化 并推导相应的雅克比矩阵 并用g2o实现相应的类 1 线特征误差及观测模型 假设相机位姿为 T c w T
  • StableDiffusion本地部署图形化训练模块(炼丹)Kohya_ss安装步骤

    将出东方
  • websocket--技术文档--spring后台+vue基本使用

    阿丹 给大家分享一个可以用来进行测试websocket的网页 个人觉得还是挺好用的 WebSocket在线测试工具 还有一个小家伙ApiPost也可以进行使用websocket的测试 本文章只是基本使用 给大家提供思路简单实现 使用spri
  • PCL 间接平差法拟合平面

    目录 一 算法原理 1 原理概述 2 参考文献 二 代码实现 三 结果展示 一 算法原理 1 原理概述 通过传统最小二乘法对点云数据进行平面拟合时 可将误差只归因于一个方向上 本文假设误差只存在于 Z Z Z轴方向上 设点云拟合的平面方程为
  • echarts中配置项splitNumber踩坑记录

    splitNumber不按照设置的数目来显示怎么办 项目问题记录 踩坑记录 合理使用boundaryGap max 实际效果 项目问题记录 项目中有九宫格式九个柱状图显示 要求y轴显示三条分割线 两个分割间隔 使用同一个option 却展示
  • datawhale-web-task02

    0 背景 完成datawhale的web入门开发task02的学习 https github com datawhalechina whale web blob master task02 md task02内容如下 用户管理 通过上节课程
  • Linux安装JDK-8-附有百度网盘链接

    前提 全新安装 Linux 64位JDK8链接 提取码 x3s4 JDK官网下载地址 http www oracle com technetwork java javase downloads jdk8 downloads 2133151
  • 安装lamp详细版本

    font face font family 宋体 font face font family Verdana p MsoNormal li MsoNormal div MsoNormal margin 0cm 0cm 0 0001pt te
  • Java - 随机文件名生成 - 根据当前时间创建文件夹 - 文件上传后,放置到指定目录下(transferTo方式)

    目录 一 随机文件名生成 具体代码演示 二 根据当前时间创建文件夹 三 文件上传后 放置到指定目录下 参考链接 一 随机文件名生成 具体代码演示 UUID 模块是内置的 public static String getRandomName
  • [论文阅读] (02) SP2019-Neural Cleanse: Identifying and Mitigating Backdoor Attacks in Neural Networks

    神经清洁 神经网络中的后门攻击识别与缓解 Neural Cleanse Identifying and Mitigating Backdoor Attacks in Neural Networks Bolun Wang Yuanshun Y
  • Qt中使用C++中的std里的线程

    加入新的类 基类一定要选择QObject 使用C 中的thread save av cpp include save av h using namespace std 加入这个就可以使用C 里面的class thread 录制音视频 voi
  • iOS开发之ReactiveCocoa框架(RAC)第五篇队列与高级函数

    h文件 import ViewController h import ReactiveCocoa interface ViewController end implementation ViewController void viewDid
  • AE中绘制图形元素的方法

    AE中绘制图形元素的方法 Element元素对象是一个非常庞杂的对象集合 主要分为两大部分 图形元素 Graphic Element 和框架元素 Frame Element 图形元素包括GroupElement MarkerElement
  • 《大话vxworks》

    目录 序言 第一章 VxWorks简介 1 1 VxWorks的起源 1 2 发展历程 1 3 应用场景 第二章 VxWorks架构
  • 拦截器源码分析

    Slf4j Controller public class BlueController ResponseBody GetMapping bb public String bb HttpSession session return sess
  • 升序定时器的时间链表的完全实现

    李邦柱 helpylee 126 com 1 定时器简介 定时器通常包含至少两个成员 一个超时时间 通常采用相对时间或者超时时间 和一个超时时间到达后的一个回调函数 有时候还可能包含回调函数被执行时需要传入的参数 以及是否重新启动定时器 更