この記事では、ループ配列に基づく単純なタイムホイールタイマーを実装します。
タイマーは、シングルショットまたは周期的にトリガーできます。タイマーは毎秒グリッドを下回り、トリガーされるイベントについてアレイノードをスキャンします。グリッド内に複数のノードが存在する可能性があり、レベル0のノードがトリガーされます。この例は比較的単純で、アラームシステムコールを介して実装されます。アラームはSIGALRMシグナルを送信して、ティック関数の実行をトリガーします。
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#define TIME_WHEEL_SIZE 8 // 轮子大小
typedef void (*func_t)(int data); // 回调函数类型
// 时间轮节点
struct timer_node {
int rotation; //轮数,有多少轮
func_t func; // 回调函数
int data; // 回调函数的参数
struct timer_node *next; // 下一个节点
};
// 时间轮
struct timer_wheel {
struct timer_node *slot[TIME_WHEEL_SIZE]; //节点数组
int current; // 当前节点
};
// 初始化时间轮
struct timer_wheel timer = {
{0}, 0};
// 时间轮最小单元,每一秒检查一下时间轮
void tick(int signo) {
struct timer_node **cur = &timer.slot[timer.current]; //当前slot
while (*cur) {
struct timer_node *curr = *cur;
if (curr->rotation > 0) {
curr->rotation--;
cur = &curr->next;
} else {
curr->func(curr->data);
*cur = curr->next;
free(curr);
}
}
timer.current = (timer.current + 1) % TIME_WHEEL_SIZE;
alarm(1); // 如果要多次触发,通常的做法是在这行加入alarm
}
// 添加节点
void add_timer(int len, func_t func) {
int pos = (len + timer.current) % TIME_WHEEL_SIZE; // 新增节点的位置
struct timer_node *node = malloc(sizeof(struct timer_node));
node->next = timer.slot[pos];
timer.slot[pos] = node;
node->rotation = len / TIME_WHEEL_SIZE; // 新增节点处于第几轮
node->data = 0;
node->func = func;
}
int g_sec = 0;
void do_time1(int data) {
printf("timer %s, %d\n", __FUNCTION__, g_sec++);
add_timer(1, do_time1); // 循环添加
}
// 只打印一次
void do_time2(int data) { printf("timer %s, %d\n", __FUNCTION__, g_sec++); }
int main(int argc, char const *argv[]) {
signal(SIGALRM, tick);
alarm(1);
add_timer(1, do_time1);
add_timer(3, do_time2);
add_timer(15, do_time2);
// alarm(1);// signal只生效一次,之后恢复默认,多次调用alarm不会回调
while (1) pause();
return 0;
}
参照:
[1] Linux C / C ++タイマーの実現原理と使用方法