国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

Linux高性能編程-時(shí)間輪

系統(tǒng) Linux
時(shí)間輪盤由固定數(shù)量槽位(wheelSize)構(gòu)成,每個(gè)槽位對(duì)應(yīng)一個(gè)時(shí)間跨度(tickMS),wheelSize*tickMS為時(shí)間輪最大時(shí)間跨度,定時(shí)任務(wù)的最大定時(shí)時(shí)間不能超過最高級(jí)時(shí)間輪的最大時(shí)間跨度。

大家好,這里是物聯(lián)網(wǎng)心球。

本期我們來聊聊時(shí)間輪,話不多說我們直接開始今天的主題。

1.初識(shí)時(shí)間輪

時(shí)間輪(TimingWheel)是一個(gè)環(huán)形隊(duì)列,底層采用數(shù)組實(shí)現(xiàn),數(shù)組中每個(gè)元素都是一個(gè)鏈表,鏈表中存儲(chǔ)的是一個(gè)個(gè)定時(shí)任務(wù)。

定時(shí)任務(wù)可以分為:延時(shí)任務(wù),周期性任務(wù)。

時(shí)間輪是一種非常重要的機(jī)制,通過時(shí)間輪可以輕松實(shí)現(xiàn)各種功能:

  • 心跳機(jī)制。
  • 周期性獲取系統(tǒng)狀態(tài)。
  • 計(jì)時(shí)功能。
  • 通知功能。
  • ......

很多著名的開源軟件都使用了時(shí)間輪,如:kafka,skynet,Linux內(nèi)核等。

所以實(shí)現(xiàn)一個(gè)高效的時(shí)間輪對(duì)于我們的軟件非常重要。

2.時(shí)間輪實(shí)現(xiàn)原理

2.1 時(shí)間輪整體架構(gòu)

圖片圖片

時(shí)間輪主要由:時(shí)間輪盤,時(shí)間指針,定時(shí)任務(wù),時(shí)間驅(qū)動(dòng)器四部分組成。

1)時(shí)間輪盤

時(shí)間輪盤由固定數(shù)量槽位(wheelSize)構(gòu)成,每個(gè)槽位對(duì)應(yīng)一個(gè)時(shí)間跨度(tickMS),wheelSize*tickMS為時(shí)間輪最大時(shí)間跨度,定時(shí)任務(wù)的最大定時(shí)時(shí)間不能超過最高級(jí)時(shí)間輪的最大時(shí)間跨度。

定時(shí)任務(wù)的最小定時(shí)時(shí)間不能低于最低級(jí)時(shí)間輪的tickMS。

時(shí)間指針會(huì)記錄時(shí)間輪的槽位位置,當(dāng)時(shí)間指針指向一個(gè)槽位時(shí),表示該槽位的任務(wù)鏈表中的任務(wù)需要被處理,如果當(dāng)前時(shí)間到達(dá)任務(wù)的到期時(shí)間(expire time)則執(zhí)行任務(wù)的回調(diào)函數(shù),否則任務(wù)被重映射到上一級(jí)時(shí)間輪對(duì)應(yīng)槽位。

2)時(shí)間指針

時(shí)間指針記錄當(dāng)前層級(jí)時(shí)間輪槽位位置,每一級(jí)時(shí)間輪的時(shí)間跨度不一樣,各個(gè)層級(jí)的時(shí)間輪時(shí)間指針會(huì)存在一定的倍數(shù)關(guān)系(由用戶自定義),低級(jí)時(shí)間輪時(shí)間指針轉(zhuǎn)一周之后,上一級(jí)時(shí)間輪才會(huì)移動(dòng)一個(gè)槽位。

3)定時(shí)任務(wù)

時(shí)間輪可以處理大批量定時(shí)任務(wù),定時(shí)任務(wù)以鏈表的形式存儲(chǔ)在每一個(gè)槽位,每個(gè)任務(wù)都由用戶自定義功能,且每個(gè)任務(wù)都有到期時(shí)間和周期時(shí)間記錄。

4)時(shí)間驅(qū)動(dòng)器

時(shí)間驅(qū)動(dòng)器就像電池一樣,推動(dòng)時(shí)間輪的運(yùn)轉(zhuǎn),相當(dāng)于一個(gè)定時(shí)刷新的功能模塊。時(shí)間驅(qū)動(dòng)器通常由一個(gè)單獨(dú)的線程通過sleep或者其他超時(shí)機(jī)制實(shí)現(xiàn)。

2.2 從0到1實(shí)現(xiàn)一個(gè)時(shí)間輪

要實(shí)現(xiàn)一個(gè)高效的時(shí)間輪,我們得結(jié)合具體的業(yè)務(wù)確定:

  • 每級(jí)時(shí)間輪時(shí)間跨度和大小
  • 時(shí)間輪的層級(jí)數(shù)。
  • 時(shí)間輪驅(qū)動(dòng)器類型。

接著我們就可以完成時(shí)間輪盤,時(shí)間指針,定時(shí)任務(wù),時(shí)間驅(qū)動(dòng)器的設(shè)計(jì)。

本示例:

一級(jí)時(shí)間輪:時(shí)間跨度1秒,時(shí)間輪大小256。

二級(jí)時(shí)間輪:時(shí)間跨度256 * 1秒,時(shí)間輪大小256。

二級(jí)時(shí)間輪:時(shí)間跨度256 * 256 * 1秒,時(shí)間輪大小256。

時(shí)間驅(qū)動(dòng)器:sleep和epoll可選。

2.2.1 組件設(shè)計(jì)

1)時(shí)間輪盤設(shè)計(jì)

struct tw {
    uint32_t tick_ms;
    uint32_t cur_tick;
    struct link slots[TW_LEVEL][TW_SIZE];
    pthread_spinlock_t lock;
};

時(shí)間輪盤定義了四個(gè)成員:

  • tick_ms:時(shí)間精度,最低級(jí)時(shí)間輪時(shí)間跨度。
  • cur_tick:當(dāng)前時(shí)間,通過當(dāng)前時(shí)間計(jì)算當(dāng)前時(shí)間指針,確定定時(shí)任務(wù)所在槽位。
  • slots:槽位,用于存儲(chǔ)定時(shí)任務(wù),定時(shí)任務(wù)以單鏈表形式存儲(chǔ)。TW_LEVEL:時(shí)間輪層級(jí)數(shù)。

TW_SIZE:時(shí)間輪大小(槽位數(shù)量)。

  • lock:自旋鎖,保證多線程對(duì)任務(wù)鏈表的安全操作。

2)時(shí)間指針設(shè)計(jì)

 時(shí)間指針按照時(shí)間輪的層級(jí)可以分為:一級(jí)時(shí)間指針,二級(jí)時(shí)間指針,三級(jí)時(shí)間指針,......。

代碼設(shè)計(jì)并不一定要為每個(gè)時(shí)間指針定義一個(gè)變量,我們定義一個(gè)總的時(shí)間指針,總的時(shí)間指針通過位運(yùn)算的獲取每一級(jí)時(shí)間指針。

#define TW_BITS (8)
#define TW_SIZE (1 << TW_BITS) //單級(jí)時(shí)間輪大小(槽位數(shù)量)
#define TW_MASK (TW_SIZE - 1)

#define IDX0(data) data & TW_MASK;         //獲取一級(jí)指針
#define IDX1(data) (data >> TW_BITS) & TW_MASK; //獲取二級(jí)指針
#define IDX2(data) (data >> (2 * TW_BITS)) & TW_MASK;//獲取三級(jí)指針

通過時(shí)間指針就能準(zhǔn)確定位到時(shí)間輪盤上的槽位,找到對(duì)應(yīng)的定時(shí)任務(wù)。

3)定時(shí)任務(wù)設(shè)計(jì)

圖片圖片

一個(gè)完整的定時(shí)任務(wù),需要具備:任務(wù)類型,周期時(shí)間,到期時(shí)間,回調(diào)函數(shù),回調(diào)函數(shù)參數(shù)等成員。

這樣才能完成一次性任務(wù),周期性任務(wù),自定義任務(wù)等功能。

typedef void (*func)(void *arg);
struct tw_node {
    struct link link;
    int32_t expire_tick;
    int32_t period_ticks;
    int flags;
    func cb;
    void *arg;
};
  • link:?jiǎn)蜗蜴湵砉?jié)點(diǎn),用于任務(wù)插入和移除操作。
  • expire_tick:定時(shí)任務(wù)到期時(shí)間,定時(shí)任務(wù)根據(jù)到期時(shí)間插入指定的槽位,并且更新時(shí)間輪時(shí),根據(jù)到期時(shí)間決定任務(wù)是否被執(zhí)行或者重映射。
  • period_ticks:周期性任務(wù)周期時(shí)間。
  • flags:任務(wù)類型,分為:一次性任務(wù)和周期性任務(wù)。

    #define ONESHOT_FLAG 0x1   //一次性任務(wù),只執(zhí)行一次

    #define PERIOD_FLAG  0x2     //周期性任務(wù),周期性執(zhí)行

  • cb:定時(shí)任務(wù)回調(diào)函數(shù)。
  • arg:定時(shí)任務(wù)回調(diào)函數(shù)參數(shù)。

4)時(shí)間驅(qū)動(dòng)器設(shè)計(jì)

時(shí)間輪運(yùn)轉(zhuǎn)通過時(shí)間驅(qū)動(dòng)器驅(qū)動(dòng),時(shí)間驅(qū)動(dòng)器是周期性更新時(shí)間輪的機(jī)制。目前用的比較多的方法:sleep和epoll方法。

方法1:sleep方式

void *tw_driver_thread(void *arg) {
    struct tw *tw = (struct tw *)arg;
    while(1) {
        usleep(TICK_MS * 1000);
        tw_update(tw);
    }
}

    sleep方法設(shè)計(jì)比較簡(jiǎn)單,while循環(huán)每一次循環(huán)調(diào)用usleep休眠指定的時(shí)間間隔(時(shí)間精度),休眠結(jié)束后更新時(shí)間輪指針。

方法二:epoll方式

void *tw_driver_thread(void *arg) {
    struct tw *tw = (struct tw *)arg;

    int efd = epoll_create(1024);
    if (efd == -1) {
        perror("epoll create error");
        return NULL;
    }
    struct epoll_event ev, events[MAX_EVENTS];

    while(1) {
        int nfds = epoll_wait(efd, events, MAX_EVENTS, TICK_MS);
        if (nfds == -1) {
            perror("epoll wait error");
            break;
        }

        tw_update(tw);

    }
}

epoll方式設(shè)計(jì)相對(duì)來說比較復(fù)雜,該方式借用epoll_wait超時(shí)機(jī)制實(shí)現(xiàn)精確定時(shí),epoll方式除了定時(shí)之外,還可以借用epoll實(shí)現(xiàn)網(wǎng)絡(luò)IO檢測(cè)功能。

2.2.2 接口設(shè)計(jì)

時(shí)間輪重要接口定義:

// 1.初始化時(shí)間輪
void tw_init(struct tw *tw, uint32_t tick_ms);
// 2.釋放時(shí)間輪
void tw_free(struct tw *tw);
// 3.添加定時(shí)任務(wù)
void tw_add(struct tw *tw, struct tw_node *node, bool 
nolock);
// 4.驅(qū)動(dòng)時(shí)間輪
int tw_update(struct tw *tw);

    其中tw_add和tw_update函數(shù)是難點(diǎn)和重點(diǎn)。

1)tw_add添加定時(shí)任務(wù)

圖片圖片

定時(shí)任務(wù)添加至?xí)r間輪首次到期時(shí)間=時(shí)間輪當(dāng)前時(shí)間+任務(wù)延遲時(shí)間。

通過到期時(shí)間可以計(jì)算出每級(jí)時(shí)間輪的時(shí)間指針,定時(shí)任務(wù)插入優(yōu)先級(jí):三級(jí)時(shí)間輪>二級(jí)時(shí)間輪>一級(jí)時(shí)間輪。

周期性任務(wù)執(zhí)行完后,需根據(jù)任務(wù)周期時(shí)間和當(dāng)前時(shí)間重新計(jì)算到期時(shí)間,并根據(jù)到期時(shí)間再次將任務(wù)插入時(shí)間輪。

2)tw_update驅(qū)動(dòng)時(shí)間輪

圖片圖片

時(shí)間驅(qū)動(dòng)器后定時(shí)調(diào)用tw_update函數(shù),tw_update每調(diào)用一次,時(shí)間輪的當(dāng)前時(shí)間會(huì)增加1,根據(jù)當(dāng)前時(shí)間獲取到一級(jí),二級(jí),三級(jí)時(shí)間指針。

如果一級(jí)時(shí)間指針大于0,說明此時(shí)一級(jí)時(shí)間輪還沒轉(zhuǎn)夠一周,該情況只需要處理一級(jí)時(shí)間指針指向的定時(shí)任務(wù)。

如果一級(jí)時(shí)間指針等于0,二級(jí)時(shí)間指針大于0,說明一級(jí)時(shí)間輪已經(jīng)轉(zhuǎn)了一周,此時(shí)處理二級(jí)時(shí)間指針指向定時(shí)任務(wù)。如果定時(shí)任務(wù)的過期時(shí)間和當(dāng)前時(shí)間相等,則直接調(diào)用定時(shí)任務(wù)回調(diào)函數(shù),如果不相等則將定時(shí)任務(wù)重新插入過期時(shí)間一級(jí)時(shí)間指針指向的槽位。

如果一級(jí),二級(jí)時(shí)間指針都等于0,三級(jí)時(shí)間指針大于0,說明一級(jí),二級(jí)時(shí)間輪都轉(zhuǎn)了一周,此時(shí)需要處理三級(jí)時(shí)間指針指向的定時(shí)任務(wù)。如果定時(shí)任務(wù)的過期時(shí)間和當(dāng)前時(shí)間相等,則直接調(diào)用定時(shí)任務(wù)回調(diào)函數(shù),如果不相等則將定時(shí)任務(wù)重新插入過期時(shí)間二級(jí)時(shí)間指針指向的槽位。

3.時(shí)間輪測(cè)試

3.1 測(cè)試代碼

測(cè)試代碼是一份完整的時(shí)間輪代碼,可以直接編譯測(cè)試。

時(shí)間精度1秒,時(shí)間輪大小256,采用三級(jí)時(shí)間輪。

定時(shí)任務(wù)為英雄聯(lián)盟劍圣技能冷卻,每個(gè)技能都是一個(gè)延時(shí)任務(wù):

  • Q技能:冷卻時(shí)間14秒,持續(xù)時(shí)間1秒。
  • W技能:冷卻時(shí)間35秒,持續(xù)時(shí)間5秒。
  • E技能:冷卻時(shí)間14秒,持續(xù)時(shí)間5秒。
  • R技能:冷卻時(shí)間75秒,持續(xù)時(shí)間10秒。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <stdbool.h>
#include <pthread.h>
#include <sys/time.h>
#include <sys/epoll.h>

#define TW_BITS (8)
#define TW_SIZE (1 << TW_BITS) //單級(jí)時(shí)間輪大小(槽位數(shù)量)
#define TW_MASK (TW_SIZE - 1)
#define TW_LEVEL (3) //時(shí)間輪層級(jí)數(shù)

#define IDX0(data) data & TW_MASK;
#define IDX1(data) (data >> TW_BITS) & TW_MASK;
#define IDX2(data) (data >> (2 * TW_BITS)) & TW_MASK;

#define ONESHOT_FLAG 0x1 //一次性任務(wù)
#define PERIOD_FLAG 0x2 //周期性任務(wù)

#define TICK_MS (1000) //單次延時(shí)時(shí)間,單位毫秒
#define MS_TO_TICKS(ms, tick_ms) (ms/tick_ms)

#define TW_DRIVER_TYPE (1) //時(shí)間驅(qū)動(dòng)器類型
#define SLEEP_DRIVER (0) //sleep時(shí)間驅(qū)動(dòng)器
#define EPOLL_DRIVER (1) //epoll時(shí)間驅(qū)動(dòng)器

#define MAX_EVENTS (10)

struct link {
    struct link *next;
};

void link_init(struct link *link) {
    link->next = NULL;
}

void link_add(struct link *link, struct link *it) {
    it->next = link->next;
    link->next = it;
}

struct link *link_del(struct link *link) {
    if (!link->next) return NULL;
    struct link *it = link->next;
    link->next = it->next;
    return it;
}

typedef void (*func)(void *arg);
struct tw_node {
    struct link link;
    int32_t expire_tick;
    int32_t period_ticks;
    int flags;
    func cb;
    void *arg;
    bool need_free;
};

struct tw {
    uint32_t tick_ms;
    uint32_t cur_tick;
    struct link slots[TW_LEVEL][TW_SIZE];
    pthread_spinlock_t lock;
};

struct tw_node *tw_node_new(struct tw *tw, int expire_ms, int period_ms, int flags, func cb, void *arg, bool need_free) {
    if ((expire_ms < TICK_MS) || (period_ms < TICK_MS)) {
        return NULL;
    }

    struct tw_node *node = (struct tw_node*)malloc(sizeof(struct tw_node));
    if (!node) return NULL;
    memset(node, 0, sizeof(struct tw_node));
    node->expire_tick = MS_TO_TICKS(expire_ms, tw->tick_ms);
    node->period_ticks = MS_TO_TICKS(period_ms, tw->tick_ms);
    //printf("tw node new expire tick:%u,%u, peroid ticks:%u,%u\n", expire_ms, node->expire_tick, period_ms, node->period_ticks);
    node->flags = flags;
    node->cb = cb;
    node->arg = arg;
    node->need_free = need_free;
    return node;
}

void tw_node_free(struct tw_node *node) {
    if (node->arg && node->need_free) {
        uint32_t *task_id = (uint32_t *)node->arg;
        printf("free task id:%u node\n", *task_id);
        free(node->arg);
    }
    free(node);
}

void tw_init(struct tw *tw, uint32_t tick_ms) {
    memset(tw, 0, sizeof(struct tw));
    tw->tick_ms = tick_ms;
    pthread_spin_init(&tw->lock, PTHREAD_PROCESS_PRIVATE);
}

void tw_free(struct tw *tw) {

    pthread_spin_lock(&tw->lock);
    for (uint32_t i = 0; i < TW_LEVEL; i++) {
        for (uint32_t j = 0; j < TW_SIZE; j++) {
            struct link *link = &tw->slots[i][j];
            struct link *it;
            while(it = link_del(link)) {
                printf("free i:%u, j:%u\n", i, j);
                struct tw_node *node = (struct tw_node *)it;
                tw_node_free(node);
            }
        }
    }

    pthread_spin_unlock(&tw->lock);
    pthread_spin_destroy(&tw->lock);
}

void tw_add(struct tw *tw, struct tw_node *node, bool nolock) {

    if (!nolock) pthread_spin_lock(&tw->lock);

    uint32_t expire_tick = node->expire_tick;
    node->expire_tick += tw->cur_tick;

#if 0
    printf("tw add cur tick:%u, period ticks:%u, old expire tick:%u, node expire tick:%u\n",
            tw->cur_tick,
            node->period_ticks,
            expire_tick,
            node->expire_tick);
#endif

    uint8_t idx0 = IDX0(tw->cur_tick);
    uint8_t idx1 = IDX1(tw->cur_tick);
    uint8_t idx2 = IDX2(tw->cur_tick);

    uint8_t e0 = IDX0(node->expire_tick);
    uint8_t e1 = IDX1(node->expire_tick);
    uint8_t e2 = IDX2(node->expire_tick);
    //printf("tw add e0,e1,e2:%u,%u,%u\n", e0, e1, e2);

    struct link *it = &node->link;
    if (e2 != idx2) {
        struct link *link = &tw->slots[2][e2];
        //printf("tw link add 2,e2:%u\n", e2);
        link_add(link, it);
    } else if (e1 != idx1) {
        struct link *link = &tw->slots[1][e1];
        //printf("tw link add 1,e1:%u\n", e1);
        link_add(link, it);
    } else if (e0 != idx0){
        struct link *link = &tw->slots[0][e0];
        //printf("tw link add 0,e0:%u\n", e0);
        link_add(link, it);
    }

    if (!nolock) pthread_spin_unlock(&tw->lock);
}

int tw_update(struct tw *tw) {
    pthread_spin_lock(&tw->lock);
    tw->cur_tick++;
    uint8_t idx0 = IDX0(tw->cur_tick);
    uint8_t idx1 = IDX1(tw->cur_tick);
    uint8_t idx2 = IDX2(tw->cur_tick);
    struct link active = {0};
    if ((idx0 == 0) && (idx1 == 0) && (idx2 > 0)) {
        struct link *link = &tw->slots[2][idx2];
        struct link *it;
        while(it = link_del(link)) {
            //printf("tw update cur tick:%u, idx0:%u,idx1:%u,idx2:%u\n", tw->cur_tick, idx0, idx1, idx2);
            struct tw_node *node = (struct tw_node *)it;
            uint8_t e0 = IDX0(node->expire_tick);
            uint8_t e1 = IDX1(node->expire_tick);
            if ((e0 == 0) && (e1 == 0)) {
                link_add(&active, it);
            } else if (e1 > 0) {
                struct link *l = &tw->slots[1][e1];
                link_add(l, it);
            } else {
                struct link *l = &tw->slots[0][e0];
                link_add(l, it);
            }
        }
    } else if ((idx0 == 0) && (idx1 > 0)) {
        struct link *link = &tw->slots[1][idx1];
        struct link *it;
        while(it = link_del(link)) {
            //printf("tw update cur tick:%u, idx0:%u,idx1:%u,idx2:%u\n", tw->cur_tick, idx0, idx1, idx2);
            struct tw_node *node = (struct tw_node *)it;
            uint8_t e0 = IDX0(node->expire_tick);
            if (e0 == 0) {
                link_add(&active, it);
            } else {
                struct link *l = &tw->slots[0][e0];
                link_add(l, it);
            }
        }

    } else if (idx0 > 0) {
        struct link *link = &tw->slots[0][idx0];
        struct link *it;
        while(it = link_del(link)) {
            //printf("tw update cur tick:%u, idx0:%u,idx1:%u,idx2:%u\n", tw->cur_tick, idx0, idx1, idx2);
            link_add(&active, it);
        }
    }

    struct link *it;
    while(it = link_del(&active)) {
        struct tw_node *node = (struct tw_node *)it;
        //printf("tw update callback cur tick:%u@@\n", tw->cur_tick);
        node->cb(node->arg);
        if (node->flags & PERIOD_FLAG) {
            node->expire_tick = node->period_ticks;
            tw_add(tw, node, true);
        } else {
            tw_node_free(node);
        }
    }
    pthread_spin_unlock(&tw->lock);

    return 0;
}

void get_time(char *buffer) {
    struct timeval tv;
    gettimeofday(&tv, NULL);
    strftime(buffer, 40, "%Y-%m-%d %H:%M:%S", localtime(&tv.tv_sec));
    sprintf(buffer + strlen(buffer), ".%03ld", tv.tv_usec / 1000);
}

void *tw_driver_thread(void *arg) {
    struct tw *tw = (struct tw *)arg;

#if (TW_DRIVER_TYPE == EPOLL_DRIVER)
    int efd = epoll_create(1024);
    if (efd == -1) {
        perror("epoll create error");
        return NULL;
    }
    struct epoll_event ev, events[MAX_EVENTS];
#endif

    while(1) {
#if (TW_DRIVER_TYPE == SLEEP_DRIVER)
        usleep(TICK_MS * 1000);
        tw_update(tw);
        //printf("sleep driver\n");
#else
        int nfds = epoll_wait(efd, events, MAX_EVENTS, TICK_MS);
        if (nfds == -1) {
            perror("epoll wait error");
            break;
        }

        //printf("epoll driver nfds:%d\n", nfds);
        tw_update(tw);
#endif
    }
}

struct skill {
    char skill_name[20];
    char ch;
    int cool_time;
    int duration_time;
    bool ready;
};

struct hero {
    char hero_name[20];
    struct skill Q;
    struct skill W;
    struct skill E;
    struct skill R;
};

void skill_task(void *arg) {
    struct skill *sk = (struct skill *)arg;
    sk->ready = true;
    char buf[40] = {0};
    get_time(buf);
    printf("%s %s 完成冷卻!\n", buf, sk->skill_name);
}

void *task_scheduler_thread(void *arg) {
    struct tw *tw = (struct tw *)arg;
    struct hero yi = (struct hero) {
        .hero_name = "易大師",
            .Q = {.skill_name = "Q技能", .ch = 'q', .cool_time = 14, .duration_time = 1, .ready = true},
            .W = {.skill_name = "W技能", .ch = 'w', .cool_time = 35, .duration_time = 5, .ready = true},
            .E = {.skill_name = "E技能", .ch = 'e', .cool_time = 14, .duration_time = 5, .ready = true},
            .R = {.skill_name = "R技能", .ch = 'r', .cool_time = 75, .duration_time = 10, .ready = true},
    };

    while(1) {
        int ch = getchar();
        if (ch == '\n') continue;
        switch (ch) {
            case 'q':
                if (yi.Q.ready == false) {
                    printf("%s %s 冷卻中......\n", yi.hero_name, yi.Q.skill_name);
                } else {
                    char buf[40] = {0};
                    get_time(buf);
                    printf("%s %s 施放 %s QQQQQQQQQQQQQQQ\n", buf, yi.hero_name, yi.Q.skill_name);
                    yi.Q.ready = false;
                    struct tw_node *node = tw_node_new(tw, yi.Q.cool_time * 1000, 1000, ONESHOT_FLAG, skill_task, (void *)&yi.Q, false);
                    if (!node) {
                        printf("tw node new error\n");
                        break;
                    }
                    tw_add(tw, node, false);
                }
                break;
            case 'w':
                if (yi.W.ready == false) {
                    printf("%s %s 冷卻中......\n", yi.hero_name, yi.W.skill_name);
                } else {
                    char buf[40] = {0};
                    get_time(buf);
                    printf("%s %s 施放 %s WWWWWWWWWWWWWW\n", buf, yi.hero_name, yi.W.skill_name);
                    yi.W.ready = false;
                    struct tw_node *node = tw_node_new(tw, yi.W.cool_time * 1000, 1000, ONESHOT_FLAG, skill_task, (void *)&yi.W, false);
                    if (!node) {
                        printf("tw node new error\n");
                        break;
                    }
                    tw_add(tw, node, false);
                }
                break;
            case 'e':
                if (yi.E.ready == false) {
                    printf("%s %s 冷卻中......\n", yi.hero_name, yi.E.skill_name);
                } else {
                    char buf[40] = {0};
                    get_time(buf);
                    yi.E.ready = false;
                    printf("%s %s 施放 %s EEEEEEEEEEEEEE\n", buf, yi.hero_name, yi.E.skill_name);
                    struct tw_node *node = tw_node_new(tw, yi.E.cool_time * 1000, 1000, ONESHOT_FLAG, skill_task, (void *)&yi.E, false);
                    if (!node) {
                        printf("tw node new error\n");
                        break;
                    }
                    tw_add(tw, node, false);
                }
                break;
            case 'r':
                if (yi.R.ready == false) {
                    printf("%s %s 冷卻中......\n", yi.hero_name, yi.R.skill_name);
                } else {
                    char buf[40] = {0};
                    get_time(buf);
                    printf("%s %s 施放 %s RRRRRRRRRRRRRRR\n", buf, yi.hero_name, yi.R.skill_name);
                    yi.R.ready = false;
                    struct tw_node *node = tw_node_new(tw, yi.R.cool_time * 1000, 1000, ONESHOT_FLAG, skill_task, (void *)&yi.R, false);
                    if (!node) {
                        printf("tw node new error\n");
                        break;
                    }
                    tw_add(tw, node, false);
                }
                break;
            default:
                printf("xxx無效技能:%c\n", ch);
                break;
        }
    }

    return NULL;
}

int main(int argc, char *argv[]) {

    struct tw tw;
    tw_init(&tw, TICK_MS);

    pthread_t th1;
    pthread_create(&th1, NULL, task_scheduler_thread, (void *)&tw);
    pthread_t th2;
    pthread_create(&th2, NULL, tw_driver_thread, (void *)&tw);

    pthread_join(th1, NULL);
    pthread_join(th2, NULL);

    printf("start free timewheel\n");

    tw_free(&tw);

    return 0;
}

3.2 測(cè)試結(jié)果

圖片圖片

總結(jié):

時(shí)間輪可以處理大批量延時(shí)任務(wù)和周期性任務(wù),是非常實(shí)用的一個(gè)軟件模塊,小伙伴可以自己動(dòng)手實(shí)現(xiàn)一個(gè)時(shí)間輪。

責(zé)任編輯:武曉燕 來源: 物聯(lián)網(wǎng)心球
相關(guān)推薦

2024-10-06 14:37:52

2024-09-03 09:15:37

2024-10-16 11:03:30

Linux高性能編程

2024-03-18 13:43:20

Linux架構(gòu)

2023-11-01 11:59:13

2022-03-21 14:13:22

Go語(yǔ)言編程

2023-11-01 11:27:10

Linux協(xié)程

2023-11-01 10:38:46

Linux高性能網(wǎng)絡(luò)編程

2023-11-01 10:58:31

系統(tǒng)調(diào)用高性能網(wǎng)絡(luò)編程Linux

2023-11-01 11:40:46

Linux高性能網(wǎng)絡(luò)編程工具

2023-11-01 11:51:08

Linux性能優(yōu)化

2023-11-01 11:07:05

Linux高性能網(wǎng)絡(luò)編程線程

2020-11-06 18:51:17

LinuxTCP服務(wù)器

2009-03-01 22:23:39

LinuxKernelLinuxDNA

2023-11-01 11:13:58

Linux信號(hào)處理定時(shí)器

2023-11-01 11:20:57

2023-11-01 10:43:31

Linux高性能網(wǎng)絡(luò)編程

2011-03-25 18:23:43

微軟高性能計(jì)算

2019-07-31 14:36:46

Linux服務(wù)器框架

2020-02-06 13:40:35

編程緩存優(yōu)化
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

男女啪啪在线观看| av在线影院| 免费不卡在线观看| 国产精品视频专区| 欧美一区二区三区婷婷| 日韩激情av在线播放| 99精品老司机免费视频| 精品久久久久久久久久国产| av网站一区| 国产精品麻豆久久久| 欧美日韩第二页| 久久久久亚洲蜜桃| 99爱视频在线| 久久亚洲免费视频| 国产av无码专区亚洲精品| 国产a区久久久| 男人添女荫道口喷水视频| 六月婷婷色综合| 一级黄色免费在线观看| 精品制服美女久久| 欧美中文字幕在线观看视频| 丁香激情综合国产| 久久久久久久久久久久久久国产| 久久久噜噜噜久久中文字幕色伊伊| 日本一区二区黄色| 中文子幕无线码一区tr| 国产三级视频| 性感美女久久精品| 成人a视频在线| 欧美这里有精品| 日韩欧美另类在线| 黄色软件视频在线观看| 一区二区三区高清国产| 亚洲三区欧美一区国产二区| 欧美中文字幕在线视频| 久久在线视频| 日本公妇乱淫免费视频一区三区| 久久精品国产99国产精品| 黄色大片中文字幕| 国产精品黄色在线观看| 亚洲一区在线日韩在线深爱| 欧美日韩国产欧美日美国产精品| 青青草视频在线免费直播| 中文字幕日韩av综合精品| 在线精品国产亚洲| 亚洲一区二区久久久久久| 午夜综合激情| 欧美成人免费在线观看视频| 一区在线播放视频| 尤物网址在线观看| 国产一区二区三区三区在线观看 | 久久99精品久久久久久噜噜| 中文字幕日韩在线| 91免费欧美精品| 日韩电影在线观看电影| 久久国产色av免费观看| 色综合一个色综合亚洲| a国产在线视频| 2023亚洲男人天堂| 丝袜美腿亚洲综合| www.国产在线视频| 亚洲国产精品自拍| 97超碰在线免费| 欧美在线观看视频| 九一久久久久久| 天堂影视av| 精品99999| 日韩黄色大片| 久久男人资源站| 色综合咪咪久久| 天堂va欧美ⅴa亚洲va一国产| 国产一区二区免费电影| 国产精品免费视频观看| 精灵使的剑舞无删减版在线观看| 欧美在线一级视频| 精品一二三四区| 天堂a中文在线| 久久久av免费| 亚久久调教视频| 日本福利视频| 中文字幕日韩专区| 亚洲精选国产| 男人天堂av网站| 在线精品高清中文字幕| 亚洲无毛电影| 国产主播中文字幕| 亚洲精品久久久久久久久久久| 日韩av片子| 国产成人精品无码播放| 日韩久久久精品| 天天综合亚洲| 国内自拍视频一区| 亚洲国产欧美一区| 欧美日韩亚洲一区三区| 日本成人中文字幕在线| 亚洲国模精品私拍| 国模 一区 二区 三区| 国模私拍视频| 日韩在线观看免费全| 视频一区欧美精品| av在线第一页| 91美女片黄在线观看游戏| 国产精品美女久久久久aⅴ| 欧美无毛视频| 在线视频一区观看| 91精品国产aⅴ一区二区| 欧美在线国产| 亚洲aⅴ优女av综合久久久| 欧美亚洲视频一区二区| 久久嫩草精品久久久精品一| 九色porny丨首页入口在线| 国产99在线免费| 福利微拍一区二区| 欧美a级成人淫片免费看| 三级免费网站| 欧美黄色三级网站| 黄色网在线免费看| 成人午夜视频在线观看免费| 色一情一乱一乱一91av| 亚洲动漫在线观看| 九色porny91| 久久久精品美女| 成年人国产精品| 国产69精品久久久久9999人| 欧美日韩一级在线| 亚洲精品97久久| 久久99精品久久久| 欧洲一区精品| 欧美黑人在线观看| 色黄久久久久久| 国产成人午夜电影网| 欧美成人黑人| 六月婷婷激情综合| xvideos成人免费中文版| 99免费精品视频| 国产综合色激情| 大肉大捧一进一出好爽动态图| 久久在线免费观看视频| 国产精品久久看| 欧美色图一区| 国产在线中文字幕| 日本高清不卡三区| 亚洲精品久久久久中文字幕欢迎你| 精品亚洲成a人| 欧美性xxx| 日韩中文字幕二区| 欧美亚洲免费电影| 五月天激情小说综合| 亚洲高清资源| 欲香欲色天天天综合和网| 农民人伦一区二区三区| 久久99精品国产99久久6尤物 | 欧美日韩国产高清视频| 精品久久久久一区二区国产| 国产精品一区二区三区99| 国产精品毛片aⅴ一区二区三区| 一区二区三区国产免费| 国产精品直播网红| 日韩欧美成人激情| 91一区二区三区在线观看| 神马久久av| 爱爱爱免费视频在线观看| 在线日韩av永久免费观看| 欧美高跟鞋交xxxxhd| 欧美日韩美女视频| 久久精品国产免费看久久精品| 日韩在线精品强乱中文字幕| 少妇激情av一区二区| 午夜啪啪免费视频| 久久久久久成人| 欧美色男人天堂| 精品在线观看视频| 女人抽搐喷水高潮国产精品| av网站无病毒在线| 欧美 日韩 国产在线观看| 国产精品美女久久久久久免费| 日韩视频一区在线观看| 国产视频亚洲色图| 尤物网精品视频| 久久影院一区二区三区| 日本v片在线免费观看| 97超碰国产精品| 亚洲www在线观看| 在线播放国产精品| 欧美视频在线观看免费网址| 国产成人精品免费一区二区| 婷婷亚洲最大| vam成人资源在线观看| 一级黄色在线| 国产原创中文在线观看| 岛国一区二区三区高清视频| 久久久999国产| 91精品国产麻豆国产自产在线 | 欧美不卡123| 亚洲男人电影天堂| 精品一二线国产| 国产精品久久久久蜜臀| 欧洲美女精品免费观看视频 | 福利一区福利二区微拍刺激| 成人性生交大片免费看视频在线|