小根堆定時(shí)器

// minheap.h
#ifndef _MINHEAP_H
#define _MINHEAP_H

#include <stdint.h>
#include <stdlib.h>
#include <pthread.h>


typedef struct timer_entry_s timer_entry_t;
typedef void (*timer_handler_pt)(timer_entry_t *ev);

#define TIMER_TIMEOUT (1 << 0)
#define TIMER_DELETE (1 << 1)
struct min_heap_s;
struct timer_entry_s
{
    struct min_heap *heap;
    uint32_t time;
    int min_heap_idx;
    timer_handler_pt handler;
    void *privdata;
};

typedef struct min_heap
{
    timer_entry_t **elements;
    uint32_t size;
    uint32_t capacity; // n 為實(shí)際元素個(gè)數(shù)  a 為容量
    pthread_mutex_t mtx;
} min_heap_t;

void min_heap_create(min_heap_t *heap);
void min_heap_destroy(min_heap_t *heap);
void min_heap_elem_init(timer_entry_t *elem);
int min_heap_elt_is_top(const timer_entry_t *elem);
int min_heap_is_empty(min_heap_t *heap);
unsigned min_heap_size(min_heap_t *heap);
timer_entry_t *min_heap_top(min_heap_t *heap);
int min_heap_ensure_capacity(min_heap_t *heap, unsigned n);
int min_heap_push(min_heap_t *heap, timer_entry_t *elem);
void min_heap_adjust(min_heap_t *heap, timer_entry_t *elem);
timer_entry_t *min_heap_pop(min_heap_t *heap);
int min_heap_delete(min_heap_t *heap, timer_entry_t *elem);
void min_heap_shift_up(min_heap_t *heap, unsigned int index, timer_entry_t *elem);
void min_heap_shift_down(min_heap_t *heap, unsigned int index, timer_entry_t *elem);

#endif // _MINHEAP_H
// minheap.c
#include "minheap.h"

#define min_heap_elem_greater(a, b) \
    ((a)->time > (b)->time)

int min_heap_left(min_heap_t *heap, int index)
{
    index = (index << 1) + 1;
    if (index >= heap->size)
    {
        return -1;
    }
    return index;
}

int min_heap_right(min_heap_t *heap, int index)
{
    index = (index << 1) + 2;
    if (index >= heap->size)
    {
        return -1;
    }
    return index;
}

void min_heap_create(min_heap_t *heap)
{
    heap->elements = 0;
    heap->size = 0;
    heap->capacity = 0;
}
void min_heap_destroy(min_heap_t *heap)
{
    if (heap->elements)
    {
        free(heap->elements);
    }
}
void min_heap_elem_init(timer_entry_t *elem) 
{ 
    memset(elem, 0, sizeof(timer_entry_t));
    elem->min_heap_idx = -1; 
}
int min_heap_is_empty(min_heap_t *heap) 
{ 
    return 0 == heap->size; 
}
unsigned min_heap_size(min_heap_t *heap) 
{ 
    return heap->size; 
}
timer_entry_t *min_heap_top(min_heap_t *heap) 
{
    if (heap->size)
    {
        return heap->elements[0];
    }
    return NULL;
}

int min_heap_push(min_heap_t *heap, timer_entry_t *elem)
{
    if (min_heap_ensure_capacity(heap, heap->size + 1))
    {
        return -1;
    }

    min_heap_shift_up(heap, heap->size, elem);
    heap->size++;
    return 0;
}

void min_heap_adjust(min_heap_t *heap, timer_entry_t *elem)
{
    min_heap_shift_down(heap, elem->min_heap_idx, elem);
}

timer_entry_t *min_heap_pop(min_heap_t *heap)
{
    if (heap->size <= 0)
    {
        return NULL;
    }

    timer_entry_t *root = heap->elements[0];
    timer_entry_t *last = heap->elements[heap->size - 1];
    heap->size--;
    heap->elements[heap->size] = NULL;
    min_heap_shift_down(heap, 0, last);
    root->min_heap_idx = -1;
    return root;
}

int min_heap_elt_is_top(const timer_entry_t *elem)
{
    return elem->min_heap_idx == 0;
}

int min_heap_delete(min_heap_t *heap, timer_entry_t *elem)
{
    if (heap->size <= 0)
    {
        return -1;
    }
    if (elem->min_heap_idx < 0)
    {
        return 0;
    }

    timer_entry_t *last = heap->elements[heap->size - 1];
    heap->size--;
    heap->elements[heap->size] = NULL;
    min_heap_shift_down(heap, elem->min_heap_idx, last);
    elem->min_heap_idx = -1;
    return 0;
}

int min_heap_ensure_capacity(min_heap_t *heap, unsigned n)
{
    if (heap->capacity < n)
    {
        timer_entry_t **p;
        unsigned a = heap->capacity ? heap->capacity * 2 : 8;
        if (a < n)
            a = n;
        if (!(p = (timer_entry_t **)realloc(heap->elements, a * sizeof *p)))
            return -1;
        heap->elements = p;
        heap->capacity = a;
    }
    return 0;
}

void min_heap_shift_up(min_heap_t *heap, uint32_t index, timer_entry_t *elem)
{

    while (index > 0)
    {
        uint32_t pindex = (index - 1) >> 1; // 父節(jié)點(diǎn)計(jì)算公式
        timer_entry_t *parent = heap->elements[pindex];
        if (parent->time <= elem->time) // 加等號(hào)讓后面添加的在后面執(zhí)行
        {
            break;
        }
        // 如果父節(jié)點(diǎn)比當(dāng)前節(jié)點(diǎn)大,那么交換,將父節(jié)點(diǎn)放在index位置
        heap->elements[index] = parent;
        heap->elements[index]->min_heap_idx = index;

        index = pindex;
    }
    heap->elements[index] = elem;
    heap->elements[index]->min_heap_idx = index;

    return;
}

void min_heap_shift_down(min_heap_t *heap, unsigned int index, timer_entry_t *elem)
{
    int half = heap->size >> 1; // 葉子節(jié)點(diǎn)計(jì)算公式
    // 第一個(gè)葉子節(jié)點(diǎn)的索引 == 非葉子節(jié)點(diǎn)的數(shù)量
    // 第一個(gè)葉子節(jié)點(diǎn)之后的節(jié)點(diǎn)全部為葉子節(jié)點(diǎn)
    while (index < half)
    {
        // index 的子節(jié)點(diǎn)有兩種情況撮抓,只有左節(jié)點(diǎn)和同時(shí)有兩個(gè)子節(jié)點(diǎn)
        int left_index = (index << 1) + 1;
        int right_index = (index << 1) + 2;
        timer_entry_t *left = heap->elements[left_index];
        timer_entry_t *child = left;
        int child_index = left_index;
        if ((right_index < heap->size) && (heap->elements[right_index]->time < child->time))
        {
            child = heap->elements[right_index];
            child_index = right_index;
        }

        if (elem->time < child->time)
        {
            break;
        }

        // 將子節(jié)點(diǎn)存到index 的位置
        heap->elements[index] = child;
        heap->elements[index]->min_heap_idx = index;
        index = child_index;
    }
    heap->elements[index] = elem;
    heap->elements[index]->min_heap_idx = index;
}
// mh-timer.h///////////////////////// 鎖未完善赁炎,另一個(gè)線程刪除定時(shí)器的時(shí)候如果定時(shí)器已經(jīng)執(zhí)行了,te 被釋放了會(huì)有問題//////////////////////////////////////////////////////////////////
#ifndef _MINHEAP_TIMER_H
#define _MINHEAP_TIMER_H

#if defined(__APPLE__)
#include <AvailabilityMacros.h>
#include <sys/time.h>
#include <mach/task.h>
#include <mach/mach.h>
#else
#include <time.h>
#endif

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include <pthread.h>

#include "minheap.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;
}

void init_timer(min_heap_t *min_heap)
{
    min_heap_create(min_heap);
    pthread_mutex_init(&min_heap->mtx, NULL);
}

timer_entry_t *add_timer(min_heap_t *min_heap, uint32_t msec, timer_handler_pt callback, void *privdata)
{
    timer_entry_t *te = (timer_entry_t *)malloc(sizeof(*te));
    if (!te)
    {
        return NULL;
    }
    min_heap_elem_init(te);
    te->handler = callback;
    te->time = current_time() + msec;
    te->privdata = privdata;
    te->heap = min_heap;

    pthread_mutex_lock(&min_heap->mtx);
    if (0 != min_heap_push(min_heap, te))
    {
        pthread_mutex_unlock(&min_heap->mtx);
        free(te);
        return NULL;
    }
    pthread_mutex_unlock(&min_heap->mtx);
    printf("[add timer] %p, time = %u now = %u\n", te, te->time, current_time());
    return te;
}

int del_timer(min_heap_t *min_heap, timer_entry_t *elem)
{
    int ret = 0;
    pthread_mutex_lock(&min_heap->mtx);
    ret = min_heap_delete(min_heap, elem);
    pthread_mutex_unlock(&min_heap->mtx);
    
    return ret;
}

int find_nearest_expire_timer(min_heap_t *min_heap)
{
    pthread_mutex_lock(&min_heap->mtx);
    timer_entry_t *te = min_heap_top(min_heap);
    if (!te)
    {
        pthread_mutex_unlock(&min_heap->mtx);
        return -1;
    }
    int diff = (int)te->time - (int)current_time();
    pthread_mutex_unlock(&min_heap->mtx);
    return diff > 0 ? diff : 0;
}

void expire_timer(min_heap_t *min_heap)
{
    uint32_t cur = current_time();
    for (;;)
    {
        pthread_mutex_lock(&min_heap->mtx);
        timer_entry_t *te = min_heap_top(min_heap);
        if (!te)
        {
            pthread_mutex_unlock(&min_heap->mtx);
            break;
        }

        if (te->time > cur)
        {
            pthread_mutex_unlock(&min_heap->mtx);
            break;
        }
        min_heap_pop(min_heap);
        pthread_mutex_unlock(&min_heap->mtx);
        te->handler(te);
        printf("[del timer] %p\n", te);
        free(te);
        te = NULL;
    }
}

#endif // _MINHEAP_TIMER_H
// mh-timer.c

#include <stdio.h>
#include <unistd.h>
#include <sys/epoll.h>
#include "mh-timer.h"

uint32_t count = 1;

void hello_world(timer_entry_t *te)
{
    if (count == 1)
    {
        count = te->time;
    }
    if (te->time < count)
    {
        printf("hello world time = %u, count = %d\n", te->time, (int)te->privdata);
        printf("dtwdebug >>>>>>>>>>>>>>>> error\n");
        exit(1);
    }
    printf("hello world time = %u, count = %d\n", te->time, (int)te->privdata);
    count = te->time;
    // add_timer(te->heap, 1000, hello_world, te->privdata);
    // del_timer(te->min_heap_idx, te);
    return;
}

int main()
{
    min_heap_t min_heap;
    init_timer(&min_heap);

    // timer_entry_t *te1 = add_timer(&min_heap, 100, hello_world, 100);
    // timer_entry_t *te2 = add_timer(&min_heap, 5000, hello_world, 5000);
    // timer_entry_t *te3 = add_timer(&min_heap, 20000, hello_world, 20000);
    // timer_entry_t *te4 = add_timer(&min_heap, 5000, hello_world, 5000);
    // timer_entry_t *te5 = add_timer(&min_heap, 6000, hello_world, 6000);
    // timer_entry_t *te6 = add_timer(&min_heap, 4000, hello_world, 4000);
    // timer_entry_t *te7 = add_timer(&min_heap, 3000, hello_world, 3000);
    // timer_entry_t *te8 = add_timer(&min_heap, 2500, hello_world, 2500);
    // timer_entry_t *te9 = add_timer(&min_heap, 150, hello_world, 160);
    // timer_entry_t *te10 = add_timer(&min_heap, 770, hello_world, 770);
    // timer_entry_t *te11 = add_timer(&min_heap, 5689, hello_world, 5689);
    // timer_entry_t *te12 = add_timer(&min_heap, 5800, hello_world, 5800);
    // timer_entry_t *te13 = add_timer(&min_heap, 60000, hello_world, 60000);
    // timer_entry_t *te14 = add_timer(&min_heap, 30000, hello_world, 30000);
    // timer_entry_t *te15 = add_timer(&min_heap, 25000, hello_world, 25000);
    // timer_entry_t *te16 = add_timer(&min_heap, 800, hello_world, 800);

    // 設(shè)置種子為當(dāng)前時(shí)間
    srand((unsigned int)time(NULL));

    for (int i = 0; i < 2000; i++)
    {
        // 生成100到25000之間的隨機(jī)數(shù)
        int random_number = 1000 + rand() % (25000 - 1000 + 1);
        add_timer(&min_heap, random_number, hello_world, random_number);
    }

    int epfd = epoll_create(1);
    struct epoll_event events[512];

    for (;;)
    {
        int nearest = find_nearest_expire_timer(&min_heap);
        int n = epoll_wait(epfd, events, 512, nearest);
        for (int i = 0; i < n; i++)
        {
            //
        }
        expire_timer(&min_heap);
    }
    return 0;
}

// gcc mh-timer.c minheap.c -o mh -I./
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末标沪,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌半火,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件季俩,死亡現(xiàn)場(chǎng)離奇詭異钮糖,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門店归,熙熙樓的掌柜王于貴愁眉苦臉地迎上來阎抒,“玉大人,你說我怎么就攤上這事消痛∏胰” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵秩伞,是天一觀的道長(zhǎng)逞带。 經(jīng)常有香客問我,道長(zhǎng)纱新,這世上最難降的妖魔是什么展氓? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮脸爱,結(jié)果婚禮上遇汞,老公的妹妹穿的比我還像新娘。我一直安慰自己簿废,他們只是感情好空入,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著捏鱼,像睡著了一般执庐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上导梆,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天轨淌,我揣著相機(jī)與錄音,去河邊找鬼看尼。 笑死递鹉,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的藏斩。 我是一名探鬼主播躏结,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼狰域!你這毒婦竟也來了媳拴?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤兆览,失蹤者是張志新(化名)和其女友劉穎屈溉,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抬探,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡子巾,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片线梗。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡椰于,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出仪搔,到底是詐尸還是另有隱情瘾婿,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布僻造,位于F島的核電站憋他,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏髓削。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一镀娶、第九天 我趴在偏房一處隱蔽的房頂上張望立膛。 院中可真熱鬧,春花似錦梯码、人聲如沸宝泵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)儿奶。三九已至,卻和暖如春鳄抒,著一層夾襖步出監(jiān)牢的瞬間闯捎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工许溅, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瓤鼻,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓贤重,卻偏偏與公主長(zhǎng)得像茬祷,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子并蝗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容