使用跳表实现定时器
- 使用的是redis中使用的跳表结构,直接从中迁移出来并修改。
- 通过跳表实现的时间轮,查询第一个数据的时间复杂度就是O(1),插入时间复杂度就 大概率的趋向于O(logn(N))。
- 定时器本身就是从头部开始取数据,跳表这一数据结构就特别匹配定时器的实现。
文件skiplist.h
#ifndef _MARK_SKIPLIST_
#define _MARK_SKIPLIST_
#define ZSKIPLIST_MAXLEVEL 32
#define ZSKIPLIST_P 0.25
typedef struct zskiplistNode zskiplistNode;
typedef void (*handler_pt) (zskiplistNode *node);
struct zskiplistNode {
unsigned long score;
handler_pt handler;
struct zskiplistLevel {
struct zskiplistNode *forward;
} level[];
};
typedef struct zskiplist {
struct zskiplistNode *header;
int length;
int level;
} zskiplist;
zskiplist *zslCreate(void);
void zslFree(zskiplist *zsl);
zskiplistNode *zslInsert(zskiplist *zsl, unsigned long score, handler_pt func);
zskiplistNode* zslMin(zskiplist *zsl);
void zslDeleteHead(zskiplist *zsl);
void zslDelete(zskiplist *zsl, zskiplistNode* zn);
void zslPrint(zskiplist *zsl);
#endif
文件skiplist.c
#include <stdlib.h>
#include <stdio.h>
#include "skiplist.h"
void defaultHandler(zskiplistNode *node) {
}
zskiplistNode *zslCreateNode(int level, unsigned long score, handler_pt func) {
zskiplistNode *zn =
malloc(sizeof(*zn)+level*sizeof(struct zskiplistLevel));
zn->score = score;
zn->handler = func;
return zn;
}
zskiplist *zslCreate(void) {
int j;
zskiplist *zsl;
zsl = malloc(sizeof(*zsl));
zsl->level = 1;
zsl->length = 0;
zsl->header = zslCreateNode(ZSKIPLIST_MAXLEVEL,0,defaultHandler);
for (j = 0; j < ZSKIPLIST_MAXLEVEL; j++) {
zsl->header->level[j].forward = NULL;
}
return zsl;
}
void zslFree(zskiplist *zsl) {
zskiplistNode *node = zsl->header->level[0].forward, *next;
free(zsl->header);
while(node) {
next = node->level[0].forward;
free(node);
node = next;
}
free(zsl);
}
int zslRandomLevel(void) {
int level = 1;
while ((arc4random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF))
level += 1;
return (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL;
}
zskiplistNode *zslInsert(zskiplist *zsl, unsigned long score, handler_pt fun){
zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
int i, level;
x = zsl->header;
for (i = zsl->level-1; i >= 0; i--) {
while (x->level[i].forward &&
x->level[i].forward->score < score)
{
x = x->level[i].forward;
}
update[i] = x;
}
level = zslRandomLevel();
printf("zskiplist add node level = %d\n", level);
if (level > zsl->level) {
for (i = zsl->level; i < level; i++) {
update[i] = zsl->header;
}
zsl->level = level;
}
x = zslCreateNode(level,score,func);
for (i = 0; i < level; i++) {
x->level[i].forward = update[i]->level[i].forward;
update[i]->level[i].forward = x;
}
zsl->length++;
return x;
}
zskiplistNode* zslMin(zskiplist *zsl) {
zskiplistNode *x;
x = zsl->header;
return x->level[0].forward;
}
void zslDeleteHead(zskiplist *zsl) {
zskiplistNode *update[ZSKIPLIST_MAXLEVEL];
zskiplistNode *x = zslMin(zsl);
if (!x) return;
int i;
for (i = zsl->level-1; i >= 0; i--) {
if (zsl->header->level[i].forward == x) {
zsl->header->level[i].forward = x->level[i].forward;
}
}
while(zsl->level > 1 && zsl->header->level[zsl->level-1].forward == NULL)
zsl->level--;
zsl->length--;
}
void zslDeleteNode(zskiplist *zsl, zskiplistNode *x, zskiplistNode **update) {
int i;
for (i = 0; i < zsl->level; i++) {
if (update[i]->level[i].forward == x) {
update[i]->level[i].forward = x->level[i].forward;
}
}
while(zsl->level > 1 && zsl->header->level[zsl->level-1].forward == NULL)
zsl->level--;
zsl->length--;
}
void zslDelete(zskiplist *zsl, zskiplistNode* zn) {
zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
int i;
x = zsl->header;
for (i = zsl->level-1; i >= 0; i--) {
while (x->level[i].forward &&
x->level[i].forward->score < zn->score)
{
x = x->level[i].forward;
}
update[i] = x;
}
x = x->level[0].forward;
if (x && zn->score == x->score) {
zslDeleteNode(zsl, x, update);
free(x);
}
}
void zslPrint(zskiplist *zsl) {
zskiplistNode *x;
x = zsl->header;
x = x->level[0].forward;
printf("start print skiplist level = %d\n", zsl->level);
int i;
for (i = 0; i < zsl->length; i++) {
printf("skiplist ele %d: score = %lu\n", i+1, x->score);
x = x->level[0].forward;
}
}
定时器实现
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>
#include <stddef.h>
#include <time.h>
#if defined(__APPLE__)
#include <AvailabilityMacros.h>
#include <sys/time.h>
#include <mach/task.h>
#include <mach/mach.h>
#endif
#include "skiplist.h"
static uint32_t
current_time() {
uint32_t t;
#if !defined(__APPLE__) || defined(AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER)
struct timespec ti;
clock_gettime(CLOCK_MONOTONIC, &ti);
t = (uint32_t)ti.tv_sec * 1000;
t += ti.tv_nsec / 1000000;
#else
struct timeval tv;
gettimeofday(&tv, NULL);
t = (uint32_t)tv.tv_sec * 1000;
t += tv.tv_usec / 1000;
#endif
return t;
}
zskiplist *init_timer() {
return zslCreate();
}
zskiplistNode *add_timer(zskiplist *zsl, uint32_t msec, handler_pt func) {
msec += current_time();
printf("add_timer expire at msec = %u\n", msec);
return zslInsert(zsl, msec, func);
}
void del_timer(zskiplist *zsl, zskiplistNode *zn) {
zslDelete(zsl, zn);
}
void expire_timer(zskiplist *zsl) {
zskiplistNode *x;
uint32_t now = current_time();
for (;;) {
x = zslMin(zsl);
if (!x) break;
if (x->score > now) break;
printf("touch timer expire time=%lu, now = %u\n", x->score, now);
x->handler(x);
zslDeleteHead(zsl);
}
}
void print_hello(zskiplistNode *zn) {
printf("hello world time = %lu\n", zn->score);
}
int main()
{
zskiplist *zsl = init_timer();
add_timer(zsl, 3010, print_hello);
add_timer(zsl, 3004, print_hello);
zskiplistNode *zn = add_timer(zsl, 3005, print_hello);
del_timer(zsl, zn);
add_timer(zsl, 3008, print_hello);
add_timer(zsl, 3003, print_hello);
for (;;) {
expire_timer(zsl);
usleep(10000);
}
return 0;
}