基于时间堆的定时器

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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#ifndef MIN_HEAP
#define MIN_HEAP

#include <iostream>
#include <netinet/in.h>
#include <time.h>
using std::exception;

#define BUFFER_SIZE 64

class heap_timer;
struct client_data {
sockaddr_in address;
int sockfd;
char buf[BUFFER_SIZE];
heap_timer* timer;
};

class heap_timer {
public:
heap_timer(int delay) {
expire = timer(NULL) + delay;
}

time_t expire;
void (*cb_func)(client_data*);
client_data* user_data;
};

class time_heap {
public:
time_heap(int cap) throw (std::exception) : capacity(cap), cur_size(0) {
array = new heap_timer* [capacity];
if (!array) {
throw std:exception();
}
for (int i = 0; i < capacity; ++i) {
array[i] = NULL;
}
}

time_heap(heap_timer** init_array, int size, int capacity) throw (std::exception) : cur_size(size), capacity(capacity) {
if (capacity < size) {
throw std::exception();
}
array = new heap_timer* [capacity];
if (!array) {
throw std::exception();
}
for (int i = 0; i < capacity; ++i) {
array[i] = NULL;
}
if (size != 0) {
for (int i = 0; i < size; ++i) {
array[i] = init_array[i];
}
for (int i = (cur_size - 1) / 2; i >= 0; --i) {
percolate_down(i);
}
}
}

~time_heap() {
for (int i = 0; i < cur_size; ++i) {
delete array[i];
}
delete[] array;
}

void add_timer(heap_timer* timer) throw (std::exception) {
if (!timer) {
return;
}
if (cur_size >= capacity) {
resize();
}
int hole = cur_size++;
int parent = 0;
for (; hole > 0; hole = parent) { // 上滤
parent = (hole - 1) / 2;
if (array[parent]->expire <= timer->expire) {
break;
}
array[hole] = array[parent];
}
array[hole] = timer;
}

void del_timer(heap_timer* timer) {
if (!timer) {
return;
}
timer->cb_func = NULL; // 所谓的延迟销毁,节省真正删除该定时器造成的开销,缺点是容易使数组膨胀
}

heap_timer* top() const {
if (empty()) {
return NULL;
}
return array[0];
}

void pop_timer() {
if (empty()) {
return;
}
if (array[0]) {
delete array[0];
array[0] = array[--cur_size];
percolate_down(0);
}
}

void tick() { // 把所有到期的事件都处理掉
heap_timer* tmp = array[0];
time_t cur = timer(NULL);
while (!empty()) {
if (!tmp) {
break;
}
if (tmp->expire > cur) {
break;
}
if (array[0]->cb_func) {
array[0]->cb_func(array[0]->user_data);
}
pop_timer();
tmp = array[0];
}
}

bool empty() const {
return cur_size == 0;
}

private:
void percolate_down(int hole) {
heap_timer* temp = array[hole];
int child = 0;
for (; ((hole * 2 + 1) <= (cur_size - 1)); hole = child) {
child = hole * 2 + 1;
if ((child < (cur_size - 1)) && (array[child + 1]->expire < array[child]->expire)) { // 右孩子比左孩子小,换右孩子
++child;
}
if (array[child]->expire < temp->expire) { // 交换操作
array[hole] = array[child];
} else {
break;
}
}
array[hole] = temp;
}

void resize() throw (std::exception) {
heap_timer** temp = new heap_timer* [2 * capacity];
for (int i = 0; i < 2 * capacity; ++i) {
temp[i] = NULL;
}
if (!temp) {
throw std::exception();
}
capacity = 2 * capacity;
for (int i = 0; i < cur_size; ++i) {
temp[i] = array[i];
}
delete[] array;
array = temp;
}

heap_timer** array;
int capacity;
int cur_size;
}

#endif

堆是一种高效的数据结构,不熟悉堆的同学先学习下堆。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
上图来自Linux高性能服务器编程——游双P211P_{211}

添加一个定时器的时间复杂度为O(log2n)O(log_2n),删除定时器复杂度为O(1)O(1),执行一个定时器时间复杂度为O(1)O(1)


reference:Linux高性能服务器编程——游双