商丘市网站建设公司/seo线下培训班

商丘市网站建设公司,seo线下培训班,政府网站源码下载,宁夏住房和城乡建设部网站1:简单基础 定时器的核心知识点,对我来说就是获取当前时间和设置回调函数。 简单练习: ​ c语言通过gettimeofday 获取当前时间并进行处理 ​ 回调函数的定义(函数参数有必要适当存储) typedef void(Timerfunc)(vo…

1:简单基础

定时器的核心知识点,对我来说就是获取当前时间和设置回调函数。

简单练习:

​ c语言通过gettimeofday 获取当前时间并进行处理

​ 回调函数的定义(函数参数有必要适当存储) typedef void(Timerfunc)(void p);

1.1 简单源码演示

#include <stdio.h>
#include <sys/time.h>
#include <unistd.h> //sleep
typedef unsigned long int uint64_t;
static uint64_t GetCurrentTime()
{struct timeval tv;gettimeofday(&tv, NULL);return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}void callback(void * p)
{int * i = (int *)p;printf("callback %d\n", *i);
}int main()
{uint64_t mytest = 1;printf("%lu \n", GetCurrentTime());sleep(2);struct timeval tv;gettimeofday(&tv, NULL);printf("second: %ld\n", tv.tv_sec); // 秒printf("millisecond: %ld\n", tv.tv_sec * 1000 + tv.tv_usec / 1000); // 毫秒printf("microsecond: %ld\n", tv.tv_sec * 1000000 + tv.tv_usec); // 徽秒sleep(3); // 让程序休眠3秒printf("---------------------sleep 3 second-------------------\n");gettimeofday(&tv, NULL);printf("second: %ld\n", tv.tv_sec); // 秒printf("millisecond: %ld\n", tv.tv_sec * 1000 + tv.tv_usec / 1000); // 毫秒printf("microsecond: %ld\n", tv.tv_sec * 1000000 + tv.tv_usec); // 徽秒
//回调函数的简单定义和使用typedef void(*Timerfunc)(void* p);int func_para = 3;Timerfunc m_func = callback;void * para = (void*)&func_para;(*m_func)(para);return 0;
}

1.2 :运行结果

root@aliy:/home/leetcode# ./get_time1 
1739506868441 
second: 1739506870
millisecond: 1739506870441
microsecond: 1739506870441927
---------------------sleep 3 second-------------------
second: 1739506873
millisecond: 1739506873442
microsecond: 1739506873442060
callback 3

2:借助已有的stl容器实现是最方便的

不知道哪里参考的一个代码,借助了stl中的一个优先级队列,就简单整理一下吧。

回顾好久没写的细节:

0:优先级队列 priority_queue 支持大堆小堆 (自己定义比较函数)

1:锁和条件变量 条件变量的几种信号等待方式。

2:chrono下的相关获取时间的接口需要梳理一下。

3:std::function 和lamba需要回顾练习一下

4:stl的push时可以直接构造结构体对象,task_queue.push(Task{func, exec_time});

5:条件变量中的wait 以及wait_until

​ ====》 已经有唤醒 wait用条件等待 防止虚假唤醒

​ ====》wait_until 接口可以实现等待到特定时间后进行执行(系统调用内部定时器实现? 会虚假唤醒吗?)。 和自己代码实现时间差同功能

在这里插入图片描述

2.1:练习源码

都是C++11的东东 需要回顾。

//定时器的简单实现  借助stl容器,使用线程进行专门的定时器处理。//容器中保存了定时器的超时时间,以及对应的回调函数 
#include <stdio.h>
#include <iostream>
#include <functional>
#include <mutex>
#include <thread>
#include <chrono>
#include <vector>
#include <condition_variable>
#include <atomic>
#include <queue>class Timer{
private:std::thread worker;std::atomic<bool> stop;//锁和条件变量std::mutex queue_mutex;std::condition_variable condition;struct Task{std::function<void(void)> func;//std::chrono::steady_clock 只能增加的单调时钟  std::chrono::time_point表示某一刻的对象//这里时间的相关接口需要参考chronostd::chrono::time_point<std::chrono::steady_clock> exec_time;  //为了给wait_until做参数 直接指定bool operator >(const Task & other) const{return exec_time > other.exec_time;}};//优先队列  用task为元素类型  以std::vector<Task> 进行存储 按照默认的比较函数进行比较  实现最小堆std::priority_queue<Task, std::vector<Task>, std::greater<Task>> task_queue; //底层是堆的结构private:void run(){while(!stop){//这里进行死循环 或者加锁条件变量实现队列中任务的提取if(task_queue.empty()){std::unique_lock<std::mutex> lock(queue_mutex);//防止虚假唤醒condition.wait(lock, [this] {return !this->task_queue.empty() || this->stop;});//这里无法访问类的成员变量 如何函数内部或者全局变量 即可以// condition.wait(lock, [] {//     return !task_queue.empty() || stop;// });}	if(task_queue.empty() || stop){return;}{// auto now  = std::chrono::steady_clock::now();auto exec_task_time = task_queue.top().exec_time; //目标执行的时间std::unique_lock<std::mutex> lock(queue_mutex);//注意第二个参数 是当前时间加上最大等待时间 if(condition.wait_until(lock, exec_task_time) == std::cv_status::timeout){auto task = task_queue.top();task_queue.pop();lock.unlock();task.func(); //这里没有定义参数  可以定义参数为自己}}}}public:Timer():stop(false), worker(&Timer::run, this){}~Timer(){ //单例时才把构造函数析构函数设置为私有stop = true;condition.notify_all();worker.join();}static inline time_t get_Clock(){// 获取当前时间点auto now = std::chrono::steady_clock::now();// 获取从纪元到现在所经过的持续时间auto duration = now.time_since_epoch();//转换为毫秒并返回return std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();}void schedule(const std::function<void()> &func, int delay_ms){auto exec_time = std::chrono::steady_clock::now() +std::chrono::milliseconds(delay_ms);{std::unique_lock<std::mutex> lock(queue_mutex);task_queue.push(Task{func, exec_time}); //注意这里的细节}condition.notify_all();}
};int main()
{Timer timer;printf("now =   %lu \n", Timer::get_Clock());timer.schedule([](){printf("exec 1000  %lu \n", Timer::get_Clock());}, 1000);timer.schedule([](){printf("exec 3000  %lu \n", Timer::get_Clock());}, 3000);std::this_thread::sleep_for(std::chrono::seconds(5));return 0;
}

2.2 :运行结果

oot@aliy:/home/leetcode# g++ my_timer1.c -o my_timer -std=c++11
root@aliy:/home/leetcode# ./my_timer 
now =   16306525752 
exec 1000  16306526753 
exec 3000  16306528753 

3:总结一些其他遗留

定时器的实现中,往往需要数据结构配合。(时间戳和回调 需要支持排序 需要方便插入)

1:红黑树存储数据结构 比如set map mutilset mutilmap 以及nginx下封装的红黑树。

2:使用最小堆进行存储。

3:跳表(有序,可以快速插入 参考redis中的跳表源码)/时间轮定时器。

3.1:时间轮定时器

在这里插入图片描述

3.2:一个来自别人的demo代码练习

在这里插入图片描述

std::vector 模拟数据结构

这样设计有最大超时时间限制吧,然后轮询也有精度。

存储的是节点指针,增加引用计数实现多次执行,类型心跳

//时间轮定时器  采用(数组+链表)链表结合vector的方式存储数据结构   采用轮询的方式处理事件#include <unistd.h>
#include <iostream>
#include <vector>
#include <list>
using namespace std;#include <sys/time.h>//同一个指针对象 多次加入只是引用计数增加  执行次数增加。
class CTimerNode {
public:CTimerNode(int fd) : id(fd), ref(0) {}void Offline() {this->ref = 0;}//通过引用计数的方式  确定是否销毁该对象  加入时++  消费时--  //可能多次加入定时器 bool TryKill() {if (this->ref == 0) return true;DecrRef();if (this->ref == 0) {cout << id << " is killed down" << endl;return true;}cout << id << " ref is " << ref << endl;return false;}void IncrRef() {this->ref++;}protected:void DecrRef() {this->ref--;}private:int ref;int id;
};const int TW_SIZE = 16;
const int EXPIRE = 10;
const int TW_MASK = TW_SIZE - 1;
static size_t iRealTick = 0;
//链表的节点
typedef list<CTimerNode*> TimeList;
typedef TimeList::iterator TimeListIter;
//用vector+list 构造时间轮数据结构 
typedef vector<TimeList> TimeWheel;void AddTimeout(TimeWheel &tw, CTimerNode *p) {if (p) {p->IncrRef();TimeList &le = tw[(iRealTick+EXPIRE) & TW_MASK]; //基于当前的时间  放入对应的list中  le.push_back(p);}
}// 用来表示delay时间后调用 
void AddTimeoutDelay(TimeWheel &tw, CTimerNode *p, size_t delay) {if (p) {p->IncrRef();TimeList &le = tw[(iRealTick+EXPIRE+delay) & TW_MASK];le.push_back(p);}
}//命中 
void TimerShift(TimeWheel &tw)
{size_t tick = iRealTick;iRealTick++;TimeList &le = tw[tick & TW_MASK];  //每次向前走一个//循环遍历轮子 消费轮子中的第一个节点对应的list中的所有事件TimeListIter iter = le.begin();for (; iter != le.end();iter++) {CTimerNode *p = *iter;if (p && p->TryKill()) {delete p;}}le.clear();
}static time_t current_time() {time_t t;struct timeval tv;gettimeofday(&tv, NULL);t = (time_t)tv.tv_sec;return t; //这里返回的是秒
}int main ()
{TimeWheel tw(TW_SIZE);CTimerNode *p = new CTimerNode(10001);AddTimeout(tw, p); //加入时间轮定时器中AddTimeoutDelay(tw, p, 5);  //对象已经存在  5s后执行对应的回调time_t start = current_time();for (;;) {time_t now = current_time();//这里以秒为单位   进行依次命中轮询if (now - start > 0) {for (int i=0; i<now-start; i++)TimerShift(tw);start = now;cout << "check timer shift " << iRealTick <<  endl;}usleep(2500); //2500 微妙  =2.5ms}return 0;
}

3.3 :demo运行

同一个TimerNode节点,只是把指针加入了时间轮中。

每次处理节点时根据引用计数进行判断了。

root@aliy:/home/leetcode# ./wheel_timer 
check timer shift 1
check timer shift 2
check timer shift 3
check timer shift 4
check timer shift 5
check timer shift 6
check timer shift 7
check timer shift 8
check timer shift 9
check timer shift 10
10001 ref is 1
check timer shift 11
check timer shift 12
check timer shift 13
check timer shift 14
check timer shift 15
10001 is killed down

3.4:更复杂的时间轮

linux内核中使用比较复杂的时间轮来进行定时器的处理

参考时钟的时针 分针 秒针,多个类似上面的时间轮进行配合,采用不同的精度,配合实现更复杂的功能(只有第一层消费,后面的基层都是按层移动到上一层)。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/895498.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python + WhisperX:解锁语音识别的高效新姿势

大家好&#xff0c;我是烤鸭&#xff1a; 最近在尝试做视频的质量分析&#xff0c;打算利用asr针对声音判断是否有人声&#xff0c;以及识别出来的文本进行进一步操作。asr看了几个开源的&#xff0c;最终选择了openai的whisper&#xff0c;后来发现性能不行&#xff0c;又换了…

mapbox 从入门到精通 - 目录

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;mapbox 从入门到精通 文章目录 一、&#x1f340;总目录1.1 ☘️ mapbox基础1.2 ☘️…

sqlilabs--小实验

一、先盲注判断 ?id1 and sleep(2)-- 如果发现页面存在注点&#xff0c;使用时间盲注脚本进行注入 import requestsdef inject_database(url):name for i in range(1, 20): # 假设数据库名称长度不超过20low 48 # 0high 122 # zmiddle (low high) // 2while low &l…

【数字】异步FIFO面试的几个小问题与跨时钟域时序约束

入门数字设计的时候&#xff0c;跨时钟域的数据处理是绕不开的课题&#xff0c;特别是多比特数据跨时钟域时&#xff0c;都会采用异步FIFO的方法。 异步FIFO中涉及较多的考点这里记录几个以供大家参考。 1. 异步FIFO的空满判断分别在哪个域&#xff1f; 根据异步FIFO的结构&…

RabbitMQ学习—day2—安装

目录 普通Linux安装 安装RabbitMQ 1、下载 2、安装 3. Web管理界面及授权操作 Docker 安装 强力推荐学docker&#xff0c;使用docker安装 普通Linux安装 安装RabbitMQ 1、下载 官网下载地址&#xff1a;https://www.rabbitmq.com/download.html(opens new window) 这…

降本增效 - VGF 构建轻量高性能日志管理平台

VFG 技术架构 Filebeat 接收Syslog &#xff0c;并进行日志分段&#xff0c;VictoriaLogs 持久化存储日志 &#xff0c;Grafana 可视化、数据查询、告警、数据导出。 为什么要用VictoriaLogs &#xff1f; 与Elasticsearch /Grafana Loki相比几十倍的CPU/内存/存储资源占用的…

初识camel智能体(一)

同目录下配置环境变量.env&#xff0c;内容如下&#xff0c; apikey从魔搭社区获取 QWEN_API_KEY4ff3ac8f-aebc******** 先上干货代码&#xff0c;主代码如下&#xff1a; from colorama import Forefrom camel.societies import RolePlaying from camel.utils import prin…

如何保持 mysql 和 redis 中数据的一致性?PegaDB 给出答案

MySQL 与 Redis 数据保持一致性是一个常见且复杂的问题&#xff0c;一般来说需要结合多种策略来平衡性能与一致性。 传统的解决策略是先读缓存&#xff0c;未命中则读数据库并回填缓存&#xff0c;但方式这种维护成本较高。 随着云数据库技术的发展&#xff0c;目前国内云厂商…

探索ELK 的魅力

在大数据时代&#xff0c;海量日志和数据的收集、存储、处理与可视化分析变得越来越重要。而 ELK 堆栈&#xff0c;由 Elasticsearch、Logstash、Beats 和 Kibana 组成&#xff0c;正是一个强大的开源解决方案&#xff0c;帮助开发者和运维人员高效管理和分析日志数据。本文将详…

深度学习实战基础案例——卷积神经网络(CNN)基于DenseNet的眼疾检测|第4例

文章目录 前言一、数据准备二、项目实战2.1 设置GPU2.2 数据加载2.3 数据预处理2.4 数据划分2.5 搭建网络模型2.6 构建densenet1212.7 训练模型2.8 结果可视化 三、UI设计四、结果展示总结 前言 在当今社会&#xff0c;眼科疾病尤其是白内障对人们的视力健康构成了严重威胁。白…

代码随想录二叉树篇(含源码)

二叉树与递归 前言226.翻转二叉树算法思路及代码solution 1 用分解问题的思路来解决solution 2 用遍历的思路来解决 101.对称二叉树算法思路及代码solution 104.二叉树的最大深度算法思路及代码solution 1 遍历solution 2 分解问题 111.二叉树的最小深度算法思路及代码solution…

MyBatis映射文件 <resultMap> 元素详解与示例

引言 <resultMap> 是 MyBatis 中最核心的映射配置元素&#xff0c;用于解决数据库字段与 Java 对象属性之间的复杂映射问题&#xff0c;尤其是字段名不一致、嵌套对象关联、集合映射等场景。ResultMap 的设计思想是&#xff0c;对简单的语句做到零配置&#xff0c;对于复…

WIN11上使用GraalVM打包springboot3项目为本地可执行文件exe

耐心肝才能成功 概念步骤概要详细步骤一. GraalVM 17二. 安装Visual Studio 2022三. 创建springboot四. IDEA最新版或者eclipse2025调试项目五. 打包exe 概念 springboot3生成的jar编译成windows本地C文件&#xff0c;不再依赖JVM运行 WINDOW编译较为复杂&#xff0c;限制条件…

【git-hub项目:YOLOs-CPP】本地实现01:项目构建

目录 写在前面 项目介绍 最新发布说明 Segmentation示例 功能特点 依赖项 安装 克隆代码仓库 配置 构建项目 写在前面 前面刚刚实现的系列文章: 【Windows/C++/yolo开发部署01】 【Windows/C++/yolo开发部署02】 【Windows/C++/yolo开发部署03】 【Windows/C++/yolo…

超越 DeepSeek V3 -->【Qwen2.5-Max】

&#x1f525; 先说明&#xff0c;不是广子&#xff0c;不是广子&#xff01;&#xff01;&#xff01;单纯分享这个工具给大家&#xff0c;毕竟最近使用 DeepSeek 太容易崩了&#xff0c;每天深度思考一次之后就开始转圈圈用不了&#xff0c;然后就找到了这个工具使用 一、前言…

python自动化测试之Pytest框架之YAML详解以及Parametrize数据驱动!

一、YAML详解 YAML是一种数据类型&#xff0c;它能够和JSON数据相互转化&#xff0c;它本身也是有很多数据类型可以满足我们接口 的参数类型&#xff0c;扩展名可以是.yml或.yaml 作用&#xff1a; 1.全局配置文件 基础路径&#xff0c;数据库信息&#xff0c;账号信息&…

CentOS 7操作系统部署KVM软件和创建虚拟机

CentOS 7.9操作系统部署KVM软件和配置指南&#xff0c;包括如何创建一个虚拟机。 步骤 1: 检查硬件支持 首先&#xff0c;确认您的CPU支持虚拟化技术&#xff0c;并且已在BIOS中启用&#xff1a; egrep -c (vmx|svm) /proc/cpuinfo 如果输出大于0&#xff0c;则表示支持虚拟…

日本 万叶假名

万叶假名&#xff08;まんようがな&#xff0c;Manyōgana&#xff09;是一种早期的日语书写系统&#xff0c;主要用于《万叶集》等古代文献中。它的特点是完全使用汉字来表示日语的音&#xff0c;不考虑汉字的原意。可以将其视为平假名和片假名的前身。 记住是唐代的发音不是…

【鸿蒙HarmonyOS Next实战开发】实现组件动态创建和卸载-优化性能

一、简介 为了解决页面和组件加载缓慢的问题&#xff0c;ArkUI框架引入了动态操作功能&#xff0c;支持组件的预创建&#xff0c;并允许应用在运行时根据实际需求动态加载和渲染组件。 这些动态操作包括动态创建组件&#xff08;即动态添加组件&#xff09;和动态卸载组件&am…

MongoDB 7 分片副本集升级方案详解(上)

#作者&#xff1a;任少近 文章目录 前言&#xff1a;Mongodb版本升级升级步骤环境1.1环境准备1.2standalone升级1.3分片、副本集升级 前言&#xff1a;Mongodb版本升级 在开始升级之前&#xff0c;请参阅 MongoDB下个版本中的兼容性变更文档&#xff0c;以确保您的应用程序和…