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

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(使用前将#替换为@)

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

  • 【华为OD机试】战场索敌(C++ Python Java)2023 B卷

    时间限制 C C 1秒 其他语言 2秒 空间限制 C C 262144K 其他语言524288K 64bit IO Format lld 题目描述 有一个大小是N M的战场地图 被墙壁 分隔成大小不同的区域 上下左右四个方向相邻的空地 属于
  • LeetCode83: 删除排序链表中的重复元素

    给定一个已排序的链表的头 head 删除所有重复的元素 使每个元素只出现一次 返回 已排序的链表 示例 1 输入 head 1 1 2 输出 1 2 示例 2 输入 head 1 1 2 3 3 输出 1 2 3 提示 链表中节点数目在范围
  • 数据结构之链表与线性表

    数据结构之链表与线性表 线性表 顺序线性表 顺序表 顺序线性表 使用数组实现 一组地址连续的存储单元 数组大小有两种方式指定 一是静态分配 二是动态扩展 优点 随机访问特性 查找O 1 时间 存储密度高 逻辑上相邻的元素 物理上也相邻 缺点
  • 剑指offer(16)——C++实现两个链表合并

    题目 输入两个单调递增的链表 输出两个链表合成后的链表 当然我们需要合成后的链表满足单调不减规则 考察点 链表 解题思路 递归实现 比较每个节点大小 将较小的放入新链表 非递归 原理同上 完整代码 16 合并两个链表 include
  • 华为OD机试 - 解密犯罪时间(Java)

    题目描述 警察在侦破一个案件时 得到了线人给出的可能犯罪时间 形如 HH MM 表示的时刻 根据警察和线人的约定 为了隐蔽 该时间是修改过的 解密规则为 利用当前出现过的数字 构造下一个距离当前时间最近的时刻 则该时间为可能的犯罪时间 每个
  • leetcode算法面试题:对称二叉树、对链表进行插入排序、多数元素

    对称二叉树问题 给定一个二叉树 检查它是否是镜像对称的 例如 二叉树 1 2 2 3 4 4 3 是对称的 1 2 2 3 4 4 3 但是下面这个 1 2 2 null 3 null 3 则不是镜像对称的 1 2 2 3 3 参考答案 c
  • 链表指定区间反转

    题目 反转从位置 m 到 n 的链表 请使用一趟扫描完成反转 说明 1 m n 链表长度 输入 1 gt 2 gt 3 gt 4 gt 5 gt NULL m 2 n 4 输出 1 gt 4 gt 3 gt 2 gt 5 gt NULL 头
  • leetcode 142.环形链表2

    leetcode 142 环形链表2 给定一个链表的头节点 head 返回链表开始入环的第一个节点 如果链表无环 则返回 null 如果链表中有某个节点 可以通过连续跟踪 next 指针再次到达 则链表中存在环 为了表示给定链表中的环 评测
  • 4--一元多项式的乘法与加法运算

    个人题解 include
  • 单链表——多项式相加

    时间限制 1000ms 内存限制 256M 实验目的 编写代码 使用两个单链表表示下面的多项式 完成两个多项式相加 并输出相加后的多项式结果 实验要求 1 单链表的类型定义如下 typedef int datatype 结点数据类型 假设为
  • 【华为OD机试】五子棋迷(C++ Python Java)2023 B卷

    时间限制 C C 1秒 其他语言 2秒 空间限制 C C 262144K 其他语言524288K 64bit IO Format lld 题目描述 张兵和王武是五子棋迷 工作之余经常切磋棋艺 这不 这会儿又下起来了 走了一会儿 轮张兵了 对
  • <数据结构>创建一个单链表

    单链表基本操作的实现 内容 构建线性表的链式存储结构 采用动态分配方式实现单链表的初始化 数据的插入 删除 输出单链表内中各元素 求单链表的长度 实现单链表中数据结点的按值排序 实现单链表的逆置 合并两个有序的单链表 有序的a表和有序的b表
  • 【数据结构】单向链表的修改和删除

    单向链表的修改和删除 从单链表中删除一个节点思路 1 找到需要删除节点的前一个节点temp 2 temp next temp next next 3 被删除的节点 将不会有其他引用指向 会被垃圾处理机制回收 1 单向链表的修改操作 1 1
  • leetcode-合并两个有序链表(详解)

    合并两个有序链表 前言 一 题链接 题意 题思路 题思路图解 题代码 总结 前言 路漫漫及修远兮 一 题链接 题意 将两个升序链表合并为一个新的 升序 链表并返回 新链表是通过拼接给定的两个链表的所有节点组成的 输入 l1 1 2 4 l2
  • 数学(五) -- LC[415]&[455] 字符串相加与两数相加

    1 字符串相加 1 1 题目描述 给定两个字符串形式的非负整数 num1 和num2 计算它们的和并同样以字符串形式返回 你不能使用任何內建的用于处理大整数的库 比如 BigInteger 也不能直接将输入的字符串转换为整数形式 示例 1
  • 双向链表详解

    目录 一 双向链表的概念及结构 二 双向链表的方法及其实现 2 1 双向链表 2 2 addFirst int data 头插法 2 3 addLast int data 尾插法 2 4 size 链表长度 2 5 display 打印链表
  • 数据结构之双向链表,实现双向链表的增删改查

    目录 一 双向链表的定义 1 双向链表节点的定义 2 双向链表的初始化 二 双向链表的函数接口实现 1 双链表的尾插 2 双向链表的尾删 3 双向链表的头插 4 双向链表的头删 6 双向链表在pos前面插入 7 双向链表删除pos位置的节点
  • 【C++】STL中list容器内部元素的移动和交换

    文章目录 前言 一 list是什么 二 元素移动 1 插入 删除 2 切除 拼接 三 元素交换 1 元素值交换 2 元素 节点 交换 总结 前言 提示 list insert list erase list splice std iter
  • 算法题-简单系列-06-删除有序链表中重复的元素

    文章目录 1 题目 1 1 循环遍历 1 题目 1 1 循环遍历 既然连续相同的元素只留下一个 我们留下哪一个最好呢 当然是遇到的第一个元素了 因为第一个元素直接就与前面的链表节点连接好了 前面就不用管了 只需要跳过后面重复的元素 连接第一
  • 华为OD机试 C++【最大载货量】

    描述 在火车站旁的货运站 小明负责调度2K辆中转车 其中K辆用于干货 K辆用于湿货 每批到站的货物来自不同的供货商 需要按照顺序装入中转车 注意 一个供货商的货物只能装在一辆车上 不能分开 但是 一辆车可以放多个供货商的货物 问题是 要让所

随机推荐

  • 【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 定时器简介 定时器通常包含至少两个成员 一个超时时间 通常采用相对时间或者超时时间 和一个超时时间到达后的一个回调函数 有时候还可能包含回调函数被执行时需要传入的参数 以及是否重新启动定时器 更