之前实现的基于升序链表的定时器虽然能实现定时的功能,但是存在一个很明显的缺点:当定时器数量多时,插入一个定时器的时间复杂度时O(n)
,因为需要保持链表升序。而删除一个定时器的时间复杂度是O(1)
(链表是双向的)。于是出现了基于时间轮的定时器,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
| #ifndef TIME_WHEEL_TIMER #define TIME_WHEEL_TIMER
#include <time.h> #include <netinet/in.h> #include <stdio.h>
#define BUFFER_SIZE 64 class tw_timer;
struct client_data { sockaddr_in address; int sockfd; char buf[BUFFER_SIZE]; tw_timer *timer; };
class tw_timer { public: tw_timer(int rot, int ts) : next(nullptr), prev(nullptr), rotation(rot), time_slot(ts) {}
public: int rotation; int time_slot; void (*cb_func)(client_data *); client_data *user_data; tw_timer *next; tw_timer *prev; };
class time_whell { public: time_whell() : cur_slot(0) { for (int i = 0; i < N; ++i) { slots[i] = nullptr; } } ~time_whell() { for (int i = 0; i < N; ++i) { tw_timer *temp = slots[i]; while (temp) { slots[i] = temp->next; delete temp; temp = slots[i]; } } }
tw_timer *add_timer(int timeout) { if (timeout < 0) { return nullptr; } int ticks = 0;
if (timeout < SI) { ticks = 1; } else { ticks = timeout / SI; } int rotation = ticks / N; int ts = (cur_slot + (ticks % N)) % N; tw_timer *timer = new tw_timer(rotation, ts); if (!slots[ts]) { printf("add timer, rotation is %d, ts is %d, cur_slot is %d\n", rotation, ts, cur_slot); slots[ts] = timer; } else { timer->next = slots[ts]; slots[ts]->prev = timer; slots[ts] = timer; } return timer; }
void del_timer(tw_timer *timer) { if (!timer) { return; } int ts = timer->time_slot;
if (timer == slots[ts]) { slots[ts] = slots[ts]->next; if (slots[ts]) { slots[ts]->prev = nullptr; } delete timer; } else { timer->prev->next = timer->next; if (timer->next) { timer->next->prev = timer->prev; } delete timer; } }
void tick() { tw_timer *temp = slots[cur_slot]; printf("current slot is %d\n", cur_slot); while (temp) { printf("tick the timer once\n"); if (temp->rotation > 0) { temp->rotation--; temp = temp->next; } else { temp->cb_func(temp->user_data); if (temp == slots[cur_slot]) { printf("delete header in cur_slot\n"); slots[cur_slot] = temp->next; delete temp; if (slots[cur_slot]) { slots[cur_slot]->prev = nullptr; } temp = slots[cur_slot]; } else { temp->prev->next = temp->next; if (temp->next) { temp->next->prev = temp->prev; } tw_timer *temp2 = temp->next; delete temp; temp = temp2; } } } cur_slot = ++cur_slot % N; }
private: static const int N = 60; static const int SI = 1; tw_timer *slots[N]; int cur_slot; };
#endif
|