From 1ad9764ef28825065407f248cee53a39c283ed24 Mon Sep 17 00:00:00 2001 From: hongzp1994 <2562180161@qq.com> Date: Wed, 14 Sep 2022 17:16:36 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AE=9A=E6=97=B6=E5=99=A8?= =?UTF-8?q?=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ZinxTimer.cpp | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++ ZinxTimer.h | 66 ++++++++++++++++++++ 2 files changed, 235 insertions(+) create mode 100644 ZinxTimer.cpp create mode 100644 ZinxTimer.h diff --git a/ZinxTimer.cpp b/ZinxTimer.cpp new file mode 100644 index 0000000..9efd140 --- /dev/null +++ b/ZinxTimer.cpp @@ -0,0 +1,169 @@ +#include "ZinxTimer.h" +#include +using namespace std; + +ZinxTimerChannel::ZinxTimerChannel() +{} + +ZinxTimerChannel::~ZinxTimerChannel() +{} +/*创建定时器文件表*/ +bool ZinxTimerChannel::Init() +{ + bool bRet = false; + /*创建文件描述符*/ + int iFd = timerfd_create(CLOCK_MONOTONIC, 0); + if (0 <= iFd) + { + /*设置定时周期*/ + struct itimerspec period = { {1,0},{1,0} }; + if (0 == timerfd_settime(iFd, 0, &period, NULL)) + { + bRet = true; + m_TimerFd = iFd; + } + } + return bRet; +} +/*读取超时次数*/ +bool ZinxTimerChannel::ReadFd(std::string& _input) +{ + bool bRet = false; + char buf[8] = { 0 }; + + if (sizeof(buf) == read(m_TimerFd, buf, sizeof(buf))) + { + bRet = true; + //str1.assgin(char * buf, n); 将部分的前n个字节赋值给str1 + _input.assign(buf,sizeof(buf)); + } + return bRet; +} + +bool ZinxTimerChannel::WriteFd(std::string& _output) +{ + return false; +} +/*关闭定时器文件表*/ +void ZinxTimerChannel::Fini() +{ + close(m_TimerFd); + m_TimerFd = -1; +} +/*返回当前的定时器文件描述符*/ +int ZinxTimerChannel::GetFd() +{ + return m_TimerFd; +} + +std::string ZinxTimerChannel::GetChannelInfo() +{ + return "TimerFd"; +} + +/*通过烤制标准输出通道去输出hello world +继承于事件类*/ +class output_hello :public AZinxHandler { + /*信息处理函数,开发者重写该函数实现信息的处理, + 当有需要一个环节继续处理时, + 应该创建新的信息对象(堆对象)并返回指针*/ + virtual IZinxMsg* InternelHandle(IZinxMsg& _oInput) + { + auto pchannel = ZinxKernel::Zinx_GetChannel_ByInfo("stdout"); + std::string output = "hello world"; + ZinxKernel::Zinx_SendOut(output, *pchannel); + return nullptr; + } + virtual AZinxHandler* GetNextHandler(IZinxMsg& _oNextMsg) + { + return nullptr; + } + +}*pout_hello = new output_hello(); + +/*返回处理超时事件 +框架类似epoll的框架,当产生信号时自动在内核执行返回对象内的函数*/ +AZinxHandler* ZinxTimerChannel::GetInputNextStage(BytesMsg& _oInput) +{ + return &TimerOutMng::GetInstance(); +} + +TimerOutMng TimerOutMng::single; +TimerOutMng::TimerOutMng() +{ + //创建10个齿 + for (int i = 0; i < 10; i++) + { + list tmp; + m_timer_wheel.push_back(tmp); + } +} + +IZinxMsg* TimerOutMng::InternelHandle(IZinxMsg& _oInput) +{ + unsigned int iTimerOutCount = 0; + GET_REF2DATA(BytesMsg, obytes, _oInput); + obytes.szData.copy((char*) & iTimerOutCount, sizeof(iTimerOutCount), 0); + + while (iTimerOutCount-- > 0) + { + /*移动刻度*/ + cur_index++; + cur_index %= 10; + listm_cache; + /*遍历当前刻度所有节点,指向处理函数或圈数-1*/ + for (auto itr = m_timer_wheel[cur_index].begin(); itr != m_timer_wheel[cur_index].end();) + { + if ((*itr)->iCount <= 0) + { + /*缓存待处理的超时节点*/ + m_cache.push_back(*itr); + auto ptmp = *itr; + //这里的itr返回的是链表下一个事件的迭代器,不是删除的, + //所以这里要有个指针来记录删除事件的迭代器对应的指针,以便重新添加 + itr = m_timer_wheel[cur_index].erase(itr); + AddTask(ptmp); + } + else + { + (*itr)->iCount--; + itr++; + } + + } + /*统一处理待处理超时事件*/ + for (auto task : m_cache) + { + task->Proc(); + } + } + return nullptr; +} +AZinxHandler* TimerOutMng::GetNextHandler(IZinxMsg& _oNextMsg) +{ + return nullptr; +} +void TimerOutMng::AddTask(TimerOutProc* _ptask) +{ + /*计算当前任务需要放在哪个齿上*/ + int index = (_ptask->GetTimeSec()+cur_index) % 10; + /*把任务放在该齿上*/ + m_timer_wheel[index].push_back(_ptask); + /*计算所需圈数*/ + _ptask->iCount = _ptask->GetTimeSec()/10; +} +void TimerOutMng::DelTask(TimerOutProc* _ptask) +{ + /*遍历时间轮所有齿,删除掉任务*/ + for (auto &chi : m_timer_wheel) + { + for (auto task : chi) + { + if (task == _ptask) + { + chi.remove(_ptask); + return ; + } + } + } +} diff --git a/ZinxTimer.h b/ZinxTimer.h new file mode 100644 index 0000000..2fe37f3 --- /dev/null +++ b/ZinxTimer.h @@ -0,0 +1,66 @@ +#pragma once +#include +#include +#include + +class ZinxTimerChannel : + public Ichannel +{ + int m_TimerFd = -1; +public: + ZinxTimerChannel(); + virtual ~ZinxTimerChannel(); + /*创建定时器文件,并设置定时周期(产生信号的频率)*/ + virtual bool Init(); + /*读取超时次数,当时间文件描述符产生信号,就会执行一次将时间文件描述符内容 + 读取到_input中,因为有些函数周期是0.5s,但是信号周期是1s + 虽然我们没法0.5秒执行一次函数,但是我们可以读取到他的超时次数, + 变成一秒读两次*/ + virtual bool ReadFd(std::string& _input); + virtual bool WriteFd(std::string& _output); + /*关闭定时器文件*/ + virtual void Fini(); + /*获得时间文件描述符*/ + virtual int GetFd(); + + virtual std::string GetChannelInfo(); + /*返回处理超时事件管理者的对象 + 框架类似epoll的框架,当产生信号时自动在内核执行返回对象内的函数*/ + virtual AZinxHandler* GetInputNextStage(BytesMsg& _oInput); +}; + + +class TimerOutProc { +public: + /*设置信号处理函数*/ + virtual void Proc() = 0; + /*获得和设置当前事件处理周期*/ + virtual int GetTimeSec() = 0; + /*所剩圈数*/ + int iCount = -1; +}; + +class TimerOutMng :public AZinxHandler { + /*信号处理函数信息的链表*/ + std::vector> m_timer_wheel; + int cur_index =0; + /*单例模式管理信号处理函数*/ + static TimerOutMng single; + TimerOutMng(); +public: + /*每过一个设置好的的时间信号,设置好的齿轮盘指针转动一个刻度, + 并执行刻度指向的,事件链表中,圈数<=0的事件,既到达周期的事件, + 执行好后,将该事件在刻度链表上删除,并将该事件重新按时间周期 + 和之前删除的刻度,重新加载到新的对应的齿轮盘新刻度的的链表中*/ + virtual IZinxMsg* InternelHandle(IZinxMsg& _oInput)override; + /*获得或者说是设置下一个信号处理函数*/ + virtual AZinxHandler* GetNextHandler(IZinxMsg& _oNextMsg)override; + /*给时间信号管理者添加事件,在事件齿轮上添加事件*/ + void AddTask(TimerOutProc* _ptask); + /*给时间信号管理者删除事件*/ + void DelTask(TimerOutProc* _ptask); + /*时间管理类对外接口,获得对象的函数*/ + static TimerOutMng &GetInstance() { + return single; + } +}; \ No newline at end of file