|
@@ -0,0 +1,195 @@
|
|
|
+#include "tw.h"
|
|
|
+
|
|
|
+#include <iostream>
|
|
|
+#include <memory.h>
|
|
|
+#include <chrono>
|
|
|
+#include <thread>
|
|
|
+
|
|
|
+TimeWheel::TimeWheel() : m_steps(0), m_firstLevelCount(0), m_secondLevelCount(60), m_thirdLevelCount(0),
|
|
|
+ m_increaseId (0){
|
|
|
+ memset(&m_timePos, 0, sizeof(m_timePos));
|
|
|
+ }
|
|
|
+
|
|
|
+void* TimeWheel::loopForInterval(void* arg)
|
|
|
+{
|
|
|
+ if(arg == NULL) {
|
|
|
+ printf("valid parameter\n");
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+ TimeWheel* timeWheel = reinterpret_cast<TimeWheel*>(arg);
|
|
|
+ while(1) {
|
|
|
+ std::this_thread::sleep_for(std::chrono::milliseconds(timeWheel->m_steps));
|
|
|
+
|
|
|
+ TimePos pos = {0};
|
|
|
+ TimePos m_lastTimePos = timeWheel->m_timePos;
|
|
|
+
|
|
|
+ timeWheel->getTriggerTimeFromInterval(timeWheel->m_steps, pos);
|
|
|
+ timeWheel->m_timePos = pos;
|
|
|
+ {
|
|
|
+ std::unique_lock<std::mutex> lock(timeWheel->m_mutex);
|
|
|
+
|
|
|
+ if (pos.pos_min != m_lastTimePos.pos_min)
|
|
|
+ {
|
|
|
+
|
|
|
+ std::list<Event_t>* eventList = &timeWheel->m_eventSlotList[timeWheel->m_timePos.pos_min + timeWheel->m_firstLevelCount + timeWheel->m_secondLevelCount];
|
|
|
+ timeWheel->processEvent(*eventList);
|
|
|
+ eventList->clear();
|
|
|
+ }
|
|
|
+ else if (pos.pos_sec != m_lastTimePos.pos_sec)
|
|
|
+ {
|
|
|
+
|
|
|
+
|
|
|
+ std::list<Event_t>* eventList = &timeWheel->m_eventSlotList[timeWheel->m_timePos.pos_sec + timeWheel->m_firstLevelCount];
|
|
|
+ timeWheel->processEvent(*eventList);
|
|
|
+ eventList->clear();
|
|
|
+ }
|
|
|
+ else if (pos.pos_ms != m_lastTimePos.pos_ms)
|
|
|
+ {
|
|
|
+
|
|
|
+
|
|
|
+ std::list<Event_t>* eventList = &timeWheel->m_eventSlotList[timeWheel->m_timePos.pos_ms];
|
|
|
+ timeWheel->processEvent(*eventList);
|
|
|
+ eventList->clear();
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return nullptr;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void TimeWheel::initTimeWheel(int steps, int maxMin)
|
|
|
+{
|
|
|
+ if (1000 % steps != 0){
|
|
|
+ printf("invalid steps\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ m_steps = steps;
|
|
|
+ m_firstLevelCount = 1000/steps;
|
|
|
+ m_thirdLevelCount = maxMin;
|
|
|
+
|
|
|
+ m_eventSlotList.resize(m_firstLevelCount + m_secondLevelCount + m_thirdLevelCount);
|
|
|
+ int ret = pthread_create(&m_loopThread, NULL, loopForInterval, this);
|
|
|
+ if(ret != 0) {
|
|
|
+ printf("create thread error:%s\n", strerror(errno));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+void TimeWheel::createTimingEvent(int interval, EventCallback_t callback){
|
|
|
+ if(interval < m_steps || interval % m_steps != 0 || interval >= m_steps*m_firstLevelCount*m_secondLevelCount*m_thirdLevelCount){
|
|
|
+ printf("invalid interval\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ printf("start create event\n");
|
|
|
+ Event_t event = {0};
|
|
|
+ event.interval = interval;
|
|
|
+ event.cb = callback;
|
|
|
+
|
|
|
+ event.timePos.pos_min = m_timePos.pos_min;
|
|
|
+ event.timePos.pos_sec = m_timePos.pos_sec;
|
|
|
+ event.timePos.pos_ms = m_timePos.pos_ms;
|
|
|
+ event.id = createEventId();
|
|
|
+
|
|
|
+ std::unique_lock<std::mutex> lock(m_mutex);
|
|
|
+ insertEventToSlot(interval, event);
|
|
|
+ printf("create over\n");
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int TimeWheel::createEventId() {
|
|
|
+ return m_increaseId++;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void TimeWheel::getTriggerTimeFromInterval(int interval, TimePos_t &timePos) {
|
|
|
+
|
|
|
+ int curTime = getCurrentMs(m_timePos);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ int futureTime = curTime + interval;
|
|
|
+
|
|
|
+ timePos.pos_min = (futureTime/1000/60)%m_thirdLevelCount;
|
|
|
+ timePos.pos_sec = (futureTime%(1000*60))/1000;
|
|
|
+ timePos.pos_ms = (futureTime%1000)/m_steps;
|
|
|
+
|
|
|
+
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+int TimeWheel::getCurrentMs(TimePos_t timePos) {
|
|
|
+ return m_steps * timePos.pos_ms + timePos.pos_sec*1000 + timePos.pos_min*60*1000;
|
|
|
+}
|
|
|
+
|
|
|
+int TimeWheel::processEvent(std::list<Event_t> &eventList){
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ for(auto event = eventList.begin(); event != eventList.end(); event ++) {
|
|
|
+
|
|
|
+ int currentMs = getCurrentMs(m_timePos);
|
|
|
+
|
|
|
+ int lastProcessedMs = getCurrentMs(event->timePos);
|
|
|
+
|
|
|
+ int distanceMs = (currentMs - lastProcessedMs + (m_secondLevelCount+1)*60*1000)%((m_secondLevelCount+1)*60*1000);
|
|
|
+
|
|
|
+
|
|
|
+ if (event->interval == distanceMs)
|
|
|
+ {
|
|
|
+
|
|
|
+ event->cb();
|
|
|
+
|
|
|
+ event->timePos = m_timePos;
|
|
|
+
|
|
|
+ insertEventToSlot(event->interval, *event);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+
|
|
|
+ printf("event->interval != distanceMs\n");
|
|
|
+
|
|
|
+ insertEventToSlot(distanceMs, *event);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+void TimeWheel::insertEventToSlot(int interval, Event_t& event)
|
|
|
+{
|
|
|
+ printf("insertEventToSlot\n");
|
|
|
+
|
|
|
+ TimePos_t timePos = {0};
|
|
|
+
|
|
|
+
|
|
|
+ getTriggerTimeFromInterval(interval, timePos);
|
|
|
+ {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if (timePos.pos_min != m_timePos.pos_min)
|
|
|
+ {
|
|
|
+ printf("insert to %d minute\n", m_firstLevelCount + m_secondLevelCount + timePos.pos_min);
|
|
|
+ m_eventSlotList[m_firstLevelCount + m_secondLevelCount + timePos.pos_min]
|
|
|
+ .push_back(event);
|
|
|
+ }
|
|
|
+
|
|
|
+ else if (timePos.pos_sec != m_timePos.pos_sec)
|
|
|
+ {
|
|
|
+ printf("insert to %d sec\n",m_firstLevelCount + timePos.pos_sec);
|
|
|
+ m_eventSlotList[m_firstLevelCount + timePos.pos_sec].push_back(event);
|
|
|
+ }
|
|
|
+
|
|
|
+ else if (timePos.pos_ms != m_timePos.pos_ms)
|
|
|
+ {
|
|
|
+ printf("insert to %d ms\n", timePos.pos_ms);
|
|
|
+ m_eventSlotList[timePos.pos_ms].push_back(event);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return;
|
|
|
+}
|