定时器实现之跳表(三)

1.概述

        书接上回上上回定时器实现之最小堆(一)定时器实现之红黑树(二),本文是使用跳表实现定时器,跳表有序的特性不必多说,感兴趣的可自行研究。

2.代码实现

        文字无力直接肝代码吧。

//zkiplist.h
#pragma once

#define ZSKIPLIST_MAXLEVEL 32 /* Should be enough for 2^64 elements */
#define ZSKIPLIST_P 0.25      /* Skiplist P = 1/2 */

struct zskiplistNode;
struct zskiplistLevel {
        zskiplistNode *forward;
};

struct zskiplistNode {
    unsigned long long score; // 时间戳
    zskiplistLevel* level;
};

typedef struct zskiplist {
    struct zskiplistNode *header;
    int length;
    int level;
} zskiplist;

zskiplist* zslCreate();
void       zslFree(zskiplist* zsl);

bool zslInsert(zskiplist* zsl, zskiplistNode* node);
zskiplistNode* zslMin(zskiplist *zsl);

void zslDeleteHead(zskiplist* zsl);
void zslDelete(zskiplist* zsl, zskiplistNode* zn); 

int zslRandomLevel(void);
zskiplistNode* zslCreateNode(int level, unsigned long score);
void zslDeleteNode(zskiplistNode* node);
void* zslCreateLevel(int level);
//zkiplist.cpp

#include "zkiplist.h"

#include <cstdlib>

int zslRandomLevel(void) {
    int level = 1;
    while ((rand()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF))

        level += 1;
    return (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL;
}

static 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--;
}

zskiplistNode *zslCreateNode(int level, unsigned long score) {
    zskiplistNode* zn = (zskiplistNode*)malloc(sizeof(zskiplistNode) + level * sizeof(zskiplistLevel));
    zn->level = (zskiplistLevel*)malloc(level * sizeof(zskiplistLevel));
    zn->score = score;
    return zn;
}

zskiplist *zslCreate(void) {
    int j = 0;
    zskiplist* zsl = nullptr;

    zsl = (zskiplist*)malloc(sizeof(zskiplist));
    zsl->level = 1;
    zsl->length = 0;
    zsl->header = zslCreateNode(ZSKIPLIST_MAXLEVEL,0);
    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->level);
    free(zsl->header);
    while(node) {
        next = node->level[0].forward;
        free(node);
        node = next;
    }
    free(zsl);
}

bool zslInsert(zskiplist *zsl, zskiplistNode* node) {
    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 < node->score)
        {
            x = x->level[i].forward;
        }
        update[i] = x;
    }
    level = zslRandomLevel();

    if (level > zsl->level) {
        for (i = zsl->level; i < level; i++) {
            update[i] = zsl->header;
        }
        zsl->level = level;
    }

    x = node;
    for (i = 0; i < level; i++) {
        x->level[i].forward = update[i]->level[i].forward;
        update[i]->level[i].forward = node;
    }

    zsl->length++;
    return true;
}

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 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);
    }
}

void zslDeleteNode(zskiplistNode* node) {
    if(node) {
        free(node->level);
    }
}

void* zslCreateLevel(int level) {
    return malloc(level * sizeof(zskiplistLevel));
}
//main.cpp

#include "minheap.h"
#include "rbtree.h"
#include "zkiplist.h"

#include <cstdint>
#include <iostream>
#include <functional>
#include <chrono>
#include <ctime>
#include <thread>

enum TimeType {
    MIN_HEAP,
    RBTREE,
    ZKIPLIST,
};

extern "C"{
#define offsetofs(s,m) (size_t)(&reinterpret_cast<const volatile char&>((((s*)0)->m)))
#define container_of(ptr, type, member) ({                  \
    const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
    (type *)( (char *)__mptr - offsetofs(type, member) );})
}

using CallBack = std::function<void(void)>;

struct TimeNode {
    timer_entry env;
    CallBack cb;
};

struct TimeNodeRb {
    rbtree_node env;
    CallBack cb;
};

struct TimeNodeZp {
    zskiplistNode env; 
    CallBack cb;   
};

class Timer {
public:
    Timer(uint32_t size);
    Timer(uint32_t size, TimeType Type);
    Timer() = delete;
    ~Timer();

    int addTimer(uint64_t time, CallBack cb);

    void run();

    void stop();

private:
    uint64_t GetNowTime();

    void AddMinHeapTimer(uint64_t time, CallBack cb);

    void AddRbtreeTimer(uint64_t time, CallBack cb);

    void AddZskiplistTimer(uint64_t time, CallBack cb);
private:
    min_heap* _heap;
    rbtree*   _rbtree;
    bool _close;
    TimeType _Type;
    zskiplist* _zskiplist;
};

Timer::Timer(uint32_t size) {
    min_heap_init(&_heap, size);
    _close = false;
}

Timer::Timer(uint32_t size, TimeType Type) {
    switch (Type) {
    case  MIN_HEAP:
        min_heap_init(&_heap, size);
        break;
    case RBTREE:
        _rbtree = new rbtree();
        if(_rbtree) {
            _rbtree->sentinel = new rbtree_node();
            rbtree_init(_rbtree, _rbtree->sentinel);
        }
        break;
    case ZKIPLIST:
        _zskiplist = zslCreate();
    }
    _close = false;
    _Type = Type;
}

Timer::~Timer() {
    switch (_Type) {
        case MIN_HEAP:
            min_heap_free(_heap);
        break;
        case RBTREE:
            delete _rbtree->sentinel;
            delete _rbtree;      
        break;
        case ZKIPLIST:
            zslFree(_zskiplist);
        break;
    }
}

int Timer::addTimer(uint64_t time, CallBack cb) {
    switch (_Type) {
    case MIN_HEAP:
        AddMinHeapTimer(time, cb);
        break;
    case RBTREE:
        AddRbtreeTimer(time, cb);
        break;
        case ZKIPLIST:
        AddZskiplistTimer(time, cb);
        break;
    }
    return 0;
}

uint64_t Timer::GetNowTime() {
    auto now = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
    uint64_t timestamp_ms = duration.count();
    return timestamp_ms;
}

void Timer::run() {
    while(!_close) {
        uint64_t sleep = 50;
        uint64_t now = GetNowTime();
        switch (_Type) {
            case MIN_HEAP: {
                timer_entry *entry = nullptr;
                if (!min_heap_top(_heap, &entry)) {
                    if (entry->time <= now) {
                        if (!min_heap_pop(_heap, &entry)) {
                            TimeNode *node = container_of(entry, TimeNode, env);
                            if (node) {
                                node->cb();
                            }

                            delete node;
                        }
                    } else {
                        sleep = entry->time - now;
                    }
                }
            }
            case RBTREE: {
                rbtree_node* node = rbtree_min(_rbtree);
                if(!node) {
                    break;
                }

                if(node->key <= now) {
                    rbtree_delete(_rbtree, node);
                    TimeNodeRb* n = container_of(node, TimeNodeRb, env);
                    n->cb();

                    delete n;
                } else {
                    sleep = node->key - now; 
                }
            }
            case ZKIPLIST: {
                zskiplistNode* node = zslMin(_zskiplist);
                if(!node) {
                    break;
                }

                if(node->score <= now) {
                    zslDeleteHead(_zskiplist);
                    TimeNodeZp* n = container_of(node, TimeNodeZp, env);
                    if(n) {
                        n->cb();
                        zslDeleteNode(&n->env);
                        delete n;
                    }
                }else {
                    sleep = node->score - now; 
                }
            }
        }

        std::this_thread::sleep_for(std::chrono::milliseconds(sleep));
    }
}


void Timer::stop() {
    _close = true;
}

void Timer::AddMinHeapTimer(uint64_t time, CallBack cb) {
    TimeNode* node = new TimeNode();
    node->env.time = GetNowTime() + time;
    node->cb = cb;
    min_heap_push(_heap, &node->env);
}

void Timer::AddRbtreeTimer(uint64_t time, CallBack cb) {
    TimeNodeRb* node = new TimeNodeRb();
    node->env.key = GetNowTime() + time;
    node->cb = cb;
    rbtree_insert(_rbtree, &node->env);
}

void Timer::AddZskiplistTimer(uint64_t time, CallBack cb) {
    TimeNodeZp* node = new TimeNodeZp();
    node->env.score = GetNowTime() + time;
    node->env.level = (zskiplistLevel*)zslCreateLevel(zslRandomLevel());
    node->cb = cb;
    zslInsert(_zskiplist, &node->env);
}

int main(int, char**){

    Timer timer(0, ZKIPLIST);

    auto now = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
    uint64_t timestamp_ms = duration.count();
    std::cout << "Start, now time :" << timestamp_ms << std::endl;
    timer.addTimer(1000, [&](void){
        auto now = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
        uint64_t timestamp_ms = duration.count();
        std::cout << "timer 1, now time :" << timestamp_ms << std::endl;
    });

    timer.addTimer(2000, [&](void){
        auto now = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
        uint64_t timestamp_ms = duration.count();
        std::cout << "timer 2, now time :" << timestamp_ms << std::endl;
    });

    std::thread t([&](){
        timer.run();
    });
    std::this_thread::sleep_for(std::chrono::milliseconds(3000));
    timer.stop();
    t.join();

    return 0;
}

3.运行效果

         

         完成工程代码在我的Github,欢迎自行拉倒本地测试指正哦!!!

        学习参考:0voice · GitHub    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值