RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

定時(shí)器作用及實(shí)現(xiàn)定時(shí)器數(shù)據(jù)結(jié)構(gòu)選取介紹2

jf_78858299 ? 來(lái)源:程序員不是碼農(nóng) ? 作者:程序員不是碼農(nóng) ? 2023-04-21 15:20 ? 次閱讀

Skynet定時(shí)器實(shí)現(xiàn)方案

skynet中定時(shí)器數(shù)據(jù)結(jié)構(gòu)

采用時(shí)間輪方式,hash表+鏈表實(shí)現(xiàn),

struct timer_node {  //時(shí)間節(jié)點(diǎn)
 struct timer_node *next;
    uint32_t expire; //到期滴答數(shù)
};
struct link_list {  // 鏈表
  struct timer_node head;
  struct timer_node *tail;
};
struct timer {
 struct link_list near[256];  // 即將到來(lái)的定時(shí)器
    struct link_list t[4][64]; // 相對(duì)較遙遠(yuǎn)的定時(shí)器
    struct spinlock lock;
    uint32_t time;  // 記錄當(dāng)前滴答數(shù)
    uint64_t starttime;
    uint64_t current;
    uint64_t current_point;
};

其中time32位無(wú)符號(hào)整數(shù), 記錄時(shí)間片對(duì)應(yīng)數(shù)組near[256] ,表示即將到來(lái)的定時(shí)任務(wù), t[4][64],表示較為遙遠(yuǎn)的定時(shí)任務(wù)。

定時(shí)器執(zhí)行流程

圖片

skynet_time_wheel

t[3] t[2] t[1] t[0] near
26-32位 20-26位 14-20位 8-14位 0-8位
[2^(8+6x3),2^(8+6x4)-1] [2^(8+6x2),2^(8+6x3)-1] [2^(8+6),2^(8+6x2)-1] [2^8,2^(8+6) -1] [0,2^8-1]
  • 首先檢查節(jié)點(diǎn)的expiretime的高24位是否相等,相等則將該節(jié)點(diǎn)添加到expire低8位值對(duì)應(yīng)數(shù)組near的元素的鏈表中,不相等則進(jìn)行下一步
  • 檢查expiretime的高18位是否相等,相等則將該節(jié)點(diǎn)添加到expire低第9位到第14位對(duì)應(yīng)的6位二進(jìn)制值對(duì)應(yīng)數(shù)組t[0]的元素的鏈表中,否則進(jìn)行下一步
  • 檢查expiretime的高12位是否相等,相等則將該節(jié)點(diǎn)添加到expire低第15位到第20位對(duì)應(yīng)的6位二進(jìn)制值對(duì)應(yīng)數(shù)組t[1]的元素的鏈表中,如果不相等則進(jìn)行下一步
  • 檢查expiretime的高6位是否相等,相等則將該節(jié)點(diǎn)添加到expire低第21位到第26位對(duì)應(yīng)的6位二進(jìn)制值對(duì)應(yīng)數(shù)組t[2]的元素的鏈表中,如果不相等則進(jìn)行下一步
  • 將該節(jié)點(diǎn)添加到expire低第27位到第32位對(duì)應(yīng)的6位二進(jìn)制值對(duì)應(yīng)數(shù)組t[3]的元素的鏈表中

以下為具體實(shí)現(xiàn),僅貼出主要接口,具體細(xì)節(jié)請(qǐng)參考skynet源代碼。

定時(shí)器初始化
// skynet_start.c
// skynet 啟動(dòng)入口
void
skynet_start(struct skynet_config * config) {
    ...
    skynet_timer_init();
    ...
}
// skynet_timer.c
void
skynet_timer_init(void) {
    // 創(chuàng)建全局timer結(jié)構(gòu) TI
    TI  = timer_create_timer();
    uint32_t current = 0;
    systime(&TI->starttime, ¤t);
    TI->current = current;
    TI->current_point = gettime();
}
添加定時(shí)器

通過(guò)skynet_server.c中的cmd_timeout調(diào)用skynet_timeout添加新的定時(shí)器

// TI為全局的定時(shí)器指針
static struct timer * TI = NULL; 
int skynet_timeout(uint32_t handle, int time, int session) {
    ...
    struct timer_event event;
    event.handle = handle;  // callback
    eveng.session = session;
    // 添加新的定時(shí)器節(jié)點(diǎn)
    timer_add(TI, &event, sizeof(event), time);
    return session;
}
// 添加新的定時(shí)器節(jié)點(diǎn)
static void timer_add(struct timer *T, void 8arg, size_t sz, int time) {
    // 給timer_node指針?lè)峙淇臻g,還需要分配timer_node + timer_event大小的空間,
    // 之后通過(guò)node + 1可獲得timer_event數(shù)據(jù)
    struct timer_node *node = (struct timer_node *)skynet_malloc(sizeof(*node)+sz);
    memcpy(node+1,arg,sz);
    SPIN_LOCK(T);
    node->expire=time+T->time;
    add_node(T, node);
    SPIN_UNLOCK(T);
}

// 添加到定時(shí)器鏈表里,如果定時(shí)器的到期滴答數(shù)跟當(dāng)前比較近(<2^8),表示即將觸發(fā)定時(shí)器添加到T->near數(shù)組里
// 否則根據(jù)差值大小添加到對(duì)應(yīng)的T->T[i]中
static void add_node(struct timer *T, struct timer_node *node) {
    ...
}
驅(qū)動(dòng)方式

skynet啟動(dòng)時(shí),會(huì)創(chuàng)建一個(gè)線程專門(mén)跑定時(shí)器,每幀(0.0025s)調(diào)用skynet_updatetime()

// skynet_start.c
static void * 
thread_timer(void *p) {
    struct monitor * m = p;
    skynet_initthread(THREAD_TIMER);
    for (;;) {
        skynet_updatetime();  // 調(diào)用timer_update
        skynet_socket_updatetime();
        CHECK_ABORT
        wakeup(m,m->count-1);
        usleep(2500);  // 2500微秒 = 0.0025s
        if (SIG) {
            signal_hup();
            SIG = 0;
        }
    }
    ...
}

每個(gè)定時(shí)器設(shè)置一個(gè)到期滴答數(shù),與當(dāng)前系統(tǒng)的滴答數(shù)(啟動(dòng)時(shí)為0,1滴答1滴答往后跳,1滴答==0.01s ) 比較得到差值interval;

如果interval比較小(0 <= interval <= 2^8-1),表示定時(shí)器即將到來(lái),保存在第一部分前2^8個(gè)定時(shí)器鏈表中;否則找到屬于第二部分對(duì)用的層級(jí)中。

// skynet_timer.c
void 
skynet_updatetime(void) {
    ...
    uint32_t diff = (uint32_t)(cp - TI->current_point); 
    TI->current_point = cp;
    TI->current += diff;
    // diff單位為0.01s
    for (i = 0; i < diff; i++){
        timer_update(TI);        
    }
}
static void
timer_update(struct timer *T) {
    SPIN_LOCK(T);
    timer_execute(T); // 檢查T(mén)->near是否位空,有就處理到期定時(shí)器
    timer_shift(T);  // 時(shí)間片time++,移動(dòng)高24位的鏈表
    timer_execute(T);
    SPIN_UNLOCK(T);
}
// 每幀從T->near中觸發(fā)到期得定時(shí)器
static inline void
timer_execute(struct timer *T) {
  ...
}
// 遍歷處理定時(shí)器鏈表中所有的定時(shí)器
static inline void
dispatch_list(struct timer_node *current) {
    ...
}
// 將高24位對(duì)應(yīng)的4個(gè)6位的數(shù)組中的各個(gè)元素的鏈表往低位移
static void
timer_shift(struct timer *T) {
    ...
}
// 將level層的idx位置的定時(shí)器鏈表從當(dāng)前位置刪除,并重新add_node
static void move_list(struct timer *T, int level, int idx) {

}

最小堆實(shí)現(xiàn)定時(shí)器

最小堆實(shí)現(xiàn)例子:boost.asio采用二叉樹(shù),go采用四叉樹(shù), libuv

具體實(shí)現(xiàn)略。

總結(jié)

本文主要介紹定時(shí)器作用,實(shí)現(xiàn)定時(shí)器數(shù)據(jù)結(jié)構(gòu)選取,并詳細(xì)介紹了跳表,紅黑樹(shù),時(shí)間輪實(shí)現(xiàn)定時(shí)器的思路和方法。

Python人工智能編程分享 Python 相關(guān)的技術(shù)文章、工具資料視頻教程等。專注Python編程開(kāi)發(fā)學(xué)習(xí)以及人工智能、機(jī)器學(xué)習(xí)、自然語(yǔ)言處理、深度學(xué)習(xí)、圖像識(shí)別、語(yǔ)音識(shí)別、無(wú)人駕駛等前沿AI技術(shù)學(xué)習(xí)!

公眾號(hào)

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11292

    瀏覽量

    209326
  • 定時(shí)器
    +關(guān)注

    關(guān)注

    23

    文章

    3246

    瀏覽量

    114719
  • 數(shù)據(jù)結(jié)構(gòu)

    關(guān)注

    3

    文章

    573

    瀏覽量

    40123
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    定時(shí)器/計(jì)數(shù)基礎(chǔ)

    15-1.實(shí)現(xiàn)定時(shí)的方法15-2.定時(shí)器/計(jì)數(shù)結(jié)構(gòu)和工作原理 15-3.
    發(fā)表于 03-23 12:17 ?48次下載

    555定時(shí)器

    555定時(shí)器555定時(shí)器555定時(shí)器555定時(shí)器555定時(shí)器555定時(shí)器555
    發(fā)表于 11-10 17:25 ?52次下載

    基于51單片機(jī)的定時(shí)器2的操作與實(shí)現(xiàn)

    基于51單片機(jī)的定時(shí)器2的操作與實(shí)現(xiàn),51單片機(jī)定時(shí)器2的使用!
    發(fā)表于 02-22 17:53 ?14次下載

    定時(shí)器介紹

    同時(shí)用兩個(gè)定時(shí)器控制蜂鳴器發(fā)聲, 定時(shí)器0控制頻率,定時(shí)器1控制同個(gè) 頻率持續(xù)的時(shí)間,間隔2s依次輸出 1,10,50100,200400800
    發(fā)表于 02-23 15:56 ?20次下載

    52單片機(jī)——定時(shí)器2詳解

    文章目錄前言一、定時(shí)器2簡(jiǎn)述1.定時(shí)器2作用2.定時(shí)器
    發(fā)表于 11-11 12:51 ?19次下載
    52單片機(jī)——<b class='flag-5'>定時(shí)器</b><b class='flag-5'>2</b>詳解

    STC51定時(shí)器定時(shí)器中斷

    1.定義定時(shí)器介紹: 51單片機(jī)的定時(shí)器屬于單片機(jī)的內(nèi)部資源,其電路的連接和運(yùn)轉(zhuǎn)均在單片機(jī)內(nèi)部完成。2.作用
    發(fā)表于 11-22 14:51 ?5次下載
    STC51<b class='flag-5'>定時(shí)器</b>與<b class='flag-5'>定時(shí)器</b>中斷

    stm32—定時(shí)器配置

    目錄定時(shí)器組成通用寄存通用寄存簡(jiǎn)介:通用定時(shí)器 TIMx (TIM2-TIM5 )的功能:通用定時(shí)器
    發(fā)表于 11-22 17:51 ?11次下載
    stm32—<b class='flag-5'>定時(shí)器</b>配置

    STM32基于cubeMX實(shí)現(xiàn)定時(shí)器點(diǎn)燈

    Cortex M3內(nèi)核當(dāng)中的定時(shí)器,它并不屬于芯片廠商的外設(shè),也就是說(shuō)使用ARM內(nèi)核的不同廠商,都擁有基本結(jié)構(gòu)相同的系統(tǒng)定時(shí)器。主要目的是給RTOS提供時(shí)鐘節(jié)拍做時(shí)間基準(zhǔn)。基本定時(shí)器
    發(fā)表于 11-23 18:21 ?19次下載
    STM32基于cubeMX<b class='flag-5'>實(shí)現(xiàn)</b><b class='flag-5'>定時(shí)器</b>點(diǎn)燈

    STM32定時(shí)器-基本定時(shí)器

    目錄定時(shí)器分類基本定時(shí)器功能框圖講解基本定時(shí)器功能時(shí)鐘源計(jì)數(shù)時(shí)鐘計(jì)數(shù)自動(dòng)重裝載寄存
    發(fā)表于 11-23 18:21 ?31次下載
    STM32<b class='flag-5'>定時(shí)器</b>-基本<b class='flag-5'>定時(shí)器</b>

    STM32——高級(jí)定時(shí)器、通用定時(shí)器、基本定時(shí)器的區(qū)別

    STM32——高級(jí)定時(shí)器、通用定時(shí)器、基本定時(shí)器的區(qū)別
    發(fā)表于 11-26 15:21 ?110次下載
    STM32——高級(jí)<b class='flag-5'>定時(shí)器</b>、通用<b class='flag-5'>定時(shí)器</b>、基本<b class='flag-5'>定時(shí)器</b>的區(qū)別

    SysTick 定時(shí)器

    的SysTick定時(shí)器來(lái)實(shí)現(xiàn)延時(shí),可以不占用系統(tǒng)定時(shí)器,節(jié)約資源。由于SysTick是在CPU核內(nèi)部實(shí)現(xiàn)的,跟MCU外設(shè)無(wú)關(guān),因此它的代碼可以在不同廠家之間移植。本 章 將 使用系統(tǒng)滴
    發(fā)表于 12-05 14:51 ?9次下載
    SysTick <b class='flag-5'>定時(shí)器</b>

    定時(shí)器作用實(shí)現(xiàn)定時(shí)器數(shù)據(jù)結(jié)構(gòu)選取介紹1

    定時(shí)器在各種場(chǎng)景都需要用到,比如游戲的Buff實(shí)現(xiàn),Redis中的過(guò)期任務(wù),Linux中的定時(shí)任務(wù)等等。顧名思義,定時(shí)器的主要用途是執(zhí)行定時(shí)
    的頭像 發(fā)表于 04-21 15:20 ?1191次閱讀
    <b class='flag-5'>定時(shí)器</b><b class='flag-5'>作用</b>及<b class='flag-5'>實(shí)現(xiàn)</b><b class='flag-5'>定時(shí)器</b><b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b><b class='flag-5'>選取</b><b class='flag-5'>介紹</b>1

    什么是軟件定時(shí)器?軟件定時(shí)器實(shí)現(xiàn)原理

    軟件定時(shí)器是用程序模擬出來(lái)的定時(shí)器,可以由一個(gè)硬件定時(shí)器模擬出成千上萬(wàn)個(gè)軟件定時(shí)器,這樣程序在需要使用較多定時(shí)器的時(shí)候就不會(huì)受限于硬件資源的
    的頭像 發(fā)表于 05-23 17:05 ?2778次閱讀

    定時(shí)器設(shè)計(jì)實(shí)現(xiàn)

    返回ITimer類型的共享指針。其中ITimer類中定義了start和stop方法,用于啟動(dòng)或停止當(dāng)前定時(shí)器。 TimerManager還有一個(gè)內(nèi)部類TimerMessageQueue用于實(shí)現(xiàn)
    的頭像 發(fā)表于 11-08 16:50 ?598次閱讀

    定時(shí)器實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)選擇

    在后端的開(kāi)發(fā)中,定時(shí)器有很廣泛的應(yīng)用。 比如: 心跳檢測(cè) 倒計(jì)時(shí) 游戲開(kāi)發(fā)的技能冷卻 redis的鍵值的有效期等等,都會(huì)使用到定時(shí)器。 定時(shí)器實(shí)現(xiàn)
    的頭像 發(fā)表于 11-13 14:22 ?523次閱讀
    <b class='flag-5'>定時(shí)器</b>的<b class='flag-5'>實(shí)現(xiàn)</b><b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>選擇
    RM新时代网站-首页