-
Notifications
You must be signed in to change notification settings - Fork 0
/
lst_timer.h
179 lines (156 loc) · 6.49 KB
/
lst_timer.h
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
176
177
178
179
// 升序定时器链表
#ifndef LST_TIMER
#define LST_TIMER
#include<time.h>
#define BUFFER_SIZE 64
class util_timer;
struct client_data{
sockaddr_in address;
int sockfd;
char buf[BUFFER_SIZE];
util_timer* timer;
};
// 定时器类
class util_timer{
public:
util_timer(): prev(NULL), next(NULL){}
public:
time_t expire; // 任务超时时间,这里使用绝对时间
void (*cb_func)(client_data*); // 任务回调函数
// 回调函数处理的客户数据,由定时器的执行者传递给回调函数
client_data* user_data;
util_timer* prev; // 指向前一个定时器
util_timer* next; // 指向下一个定时器
};
// 定时器链表,它是一个升序、双向链表,且带有头结点和尾结点
class sort_timer_lst{
public:
sort_timer_lst(): head(NULL), tail(NULL){}
// 链表销毁时,删除其中所有的定时器
~sort_timer_lst(){
util_timer* tmp = head;
while(tmp){
head = tmp->next;
delete tmp;
tmp = head;
}
}
// 将目标定时器timer添加到链表中
void add_timer(util_timer* timer){
if(!timer){ return; }
if(!head){ head = tail = timer; }
// 如果目标定时器的超时时间小于当前链表中所有定时器的超时时间
// 则把该定时器插入链表头部,作为链表新的头结点
// 否则就需要调用重载函数add_timer(util_timer* timer, util_timer* lst_head)把它插入到合适的位置
if(timer->expire < head->expire){
timer->next = head;
head->prev = timer;
head = timer;
return;
}
addtimer(timer, head);
}
// 当某个定时任务发生变化时,调整对应的定时器在链表中的位置
// 这个函数只考虑被调整的定时器的超时时间延长的情况,即该定时器需要往链表的尾部移动
void adjust_timer(util_timer* timer){
if(!timer){ return; }
util_timer* tmp = timer->next;
// 如果被调整的目标定时器在链接尾部,或定时器的超时值仍然小于其下一个定时器的超时值,则不用调整
// 那如果被调整的目标定时器超时值也小于其前面一个定时器的值呢?
if(!tmp || (timer->expire < tmp->expire)){ return; }
// 如果目标定时器是链表的头结点,则将该定时器从链表中取出并重新插入链表
if(timer == head){
head = head->next;
head->prev = NULL;
timer->next = NULL;
add_timer(timer, head);
}
// 如果目标定时器不是链表的头结点,则将该定时器从链表中取出
// 然后插入其原来所在位置之后的部分链表中
else{
timer->prev->next = timer->next;
timer->next->prev = timer->prev;
add_timer(timer, timer->next);
}
}
// 将目标定时器timer从链表中删除
void del_timer(util_timer* timer){
if(!timer){ return; }
// 下面这个条件成立表示链表中只有一个定时器,即目标定时器
if((timer == head) && (timer==tail)){
delete timer;
head = NULL;
tail = NULL;
return;
}
// 如果链表中至少有两个定时器,且目标定时器是链表的头结点
// 则将链表的头结点重置为原结点的下一个结点,然后删除目标定时器
if(timer == head){
head = head->next;
head->prev = NULL;
delete timer;
return;
}
// 如果链表中至少有两个定时器,且目标定时器是链表的尾结点,则将链表的尾结点重置为原尾结点的前一个结点,然后删除目标定时器
if(timer == tail){
tail = tail->prev;
tail->next = NULL;
delete timer;
return;
}
// 如果目标定时器位于链表中间,则把它们前后的定时器串联起来然后删除目标定时器
timer->prev->next = timer->next;
timer->next->prev = timer->prev;
delete timer;
}
// SIGALRM信号每次触发就在其信号处理函数(如果使用统一事件源,则是主函数)中执行一次tick函数,以处理链表上到期的任务
void tick(){
if(!head){ return; }
printf("timer tick\n");
time_t cur = time(NULL); // 获得系统当前的时间
util_timer* tmp = head;
// 从头结点开始依次处理每个定时器,直到遇到一个尚未到期的定时器,这就是定时器的核心逻辑
while(tmp){
// 因为每个定时器都使用绝对时间作为超时值,所以我们可以把定时器的超时值和系统当前时间比较,以判断定时器是否到期
if(cur < tmp->expire){ break; }
// 调用定时器的回调函数,以执行定时任务
tmp->cb_func(tmp->user_data);
// 执行完定时器中的定时任务后,就将它从链表中删除,并重置链表头结点
head = tmp->next;
if(head){ head->prev = NULL; }
delete tmp;
tmp = head;
}
}
private:
// 一个重载的辅助函数,它被公有的add_timer函数和adjust_timer函数调用
// 该函数表示将目标定时器timer添加到结点lst_head之后的部分链表
void add_timer(util_timer* timer, util_timer* lst_head){
util_timer* prev = lst_head;
util_timer* tmp = prev->next;
// 遍历lst_head结点之后的部分链表,直到找到一个超时时间大于目标定时器的超时时间的结点,并将目标定时器插入到该结点之前
while(tmp){
if(timer->expire < tmp->expire){
prev->next = timer;
timer->next = tmp;
tmp->prev = timer;
timer->prev = prev;
break;
}
prev = tmp;
tmp = tmp->next;
}
// 如果遍历完lst_head节点之后的部分链表,仍未找到超时时间大于目标定时器的超时时间的节点
// 则将目标定时器插入链表尾部,并将它设置为链表新的尾结点
if(!tmp){
prev->next = timer;
timer->prev = prev;
timer->next = NULL;
tail = timer;
}
}
private:
util_timer* head;
util_timer* tail;
};
#endif