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)選取介紹1

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

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

定時(shí)器作用

定時(shí)器在各種場(chǎng)景都需要用到,比如游戲的Buff實(shí)現(xiàn),Redis中的過(guò)期任務(wù),Linux中的定時(shí)任務(wù)等等。顧名思義,定時(shí)器的主要用途是執(zhí)行定時(shí)任務(wù)。

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

定時(shí)器數(shù)據(jù)結(jié)構(gòu)要求:

  • 需要快速找到到期任務(wù),因此,應(yīng)該具有有序性;
  • 其過(guò)期執(zhí)行、插入(添加定時(shí)任務(wù))和刪除(取消定時(shí)任務(wù))的頻率比較高,三種操作效率必須保證

以下為各數(shù)據(jù)結(jié)構(gòu)時(shí)間復(fù)雜度表現(xiàn)

有序鏈表:插入O(n),刪除O(1),過(guò)期expire執(zhí)行O(1)

最小堆:插入O(logn),刪除O(logn),過(guò)期expire執(zhí)行O(1)

紅黑樹(shù):插入O(logn),刪除O(logn),過(guò)期expire執(zhí)行O(logn)

哈希表+鏈表(時(shí)間輪):插入O(1),刪除O(1),過(guò)期expire平均執(zhí)行O(1)(最壞為O(n)

不同開(kāi)源框架定時(shí)器實(shí)現(xiàn)方式不一,如,libuv采用最小堆來(lái)實(shí)現(xiàn),nginx采用紅黑樹(shù)實(shí)現(xiàn),linux內(nèi)核和skynet采用時(shí)間輪算法實(shí)現(xiàn)等等。

定時(shí)器接口封裝

作為定時(shí)器,需要封裝以下4類(lèi)接口給用戶使用:

  • 創(chuàng)建定時(shí)器:init_timer
  • 添加定時(shí)任務(wù):add_timer
  • 取消定時(shí)任務(wù):cancel_timer
  • 執(zhí)行到期任務(wù):expire_timer

其中執(zhí)行到期任務(wù)有兩種工作方式:

  1. 輪詢(xún): 每隔一個(gè)時(shí)間片去查找哪些任務(wù)到期
  2. 睡眠/喚醒:不停查找deadline最近任務(wù),到期執(zhí)行,否則sleep;sleep期間,任務(wù)有改變,線程會(huì)被喚醒

接下來(lái)將介紹分別用跳表、紅黑樹(shù)、時(shí)間輪來(lái)實(shí)現(xiàn)定時(shí)器。

跳表實(shí)現(xiàn)定時(shí)器

跳表簡(jiǎn)介

跳表是一種動(dòng)態(tài)的數(shù)據(jù)結(jié)構(gòu),采用空間換時(shí)間的思想,在有序鏈表基礎(chǔ)上加入多級(jí)索引,通過(guò)索引進(jìn)行二分快速查找,支持快速刪除、插入和查找操作(平均時(shí)間復(fù)雜度為O(logN),最壞為O(N)),效率可與平衡樹(shù)媲美,實(shí)現(xiàn)比其簡(jiǎn)單。

下面通過(guò)一張圖來(lái)簡(jiǎn)單說(shuō)明跳表操作。跳表的最底層即為基本的有序鏈表,存儲(chǔ)所有的數(shù)據(jù),可理解為數(shù)據(jù)層;往上則為索引層,理想狀態(tài)下,上一層為下一層節(jié)點(diǎn)數(shù)的一半。比如,要查找下圖的數(shù)據(jù)為11的節(jié)點(diǎn),從begin''出發(fā),向右走,如果下一個(gè)節(jié)點(diǎn)大于11則往下走,直到找到目標(biāo)節(jié)點(diǎn)??梢?jiàn),跳表要比原始鏈表少比較一些節(jié)點(diǎn),但前提是需要花更多空間存儲(chǔ)索引節(jié)點(diǎn)。

圖片

image-20210323182236910

跳表實(shí)現(xiàn)定時(shí)器

  • 跳表查找,插入,刪除(任意節(jié)點(diǎn)、頭節(jié)點(diǎn))的時(shí)間復(fù)雜度大概率趨向于O(logn)
  • 過(guò)期任務(wù)查找,只需要跟第一個(gè)節(jié)點(diǎn)比較,因其第一個(gè)節(jié)點(diǎn)即為最小節(jié)點(diǎn)

學(xué)會(huì)吸取開(kāi)源框架中優(yōu)秀數(shù)據(jù)結(jié)構(gòu)和代碼思想,直接采用redis中跳表結(jié)構(gòu)的實(shí)現(xiàn),取出所需部分,用于實(shí)現(xiàn)定時(shí)器。如下:

跳表數(shù)據(jù)結(jié)構(gòu)

跳表節(jié)點(diǎn)與跳表結(jié)構(gòu)

/*skiplist.h*/
#define ZSKIPLIST_MAXLEVEL 32
#define ZSKIPPLIST 0.25

typedef struct zskiplistNode zskiplistNode;
typedef void (*handler_pt) (zskiplistNode * node);
// 跳表節(jié)點(diǎn)
struct zskiplistNode {
  unsigned long score;  /*用于排序的值*/
  handler_pt handler;  /*處理函數(shù)*/
  struct zskiplistLevel {
    struct zskiplistNode **forward;
  }level[];
};
// 跳表結(jié)構(gòu)
typedef struct zskiplist {
  struct zskiplistNode * header;
  int length;
  int level;  /*跳表層數(shù)*/
}zskiplist;

跳表接口申明

具體接口實(shí)現(xiàn)細(xì)節(jié)請(qǐng)移步redis源碼。

/*skiplist.h*/
/*創(chuàng)建跳表,初始化*/
zskiplist *zslCreate(void);
/*刪除跳,表釋放資源*/
void zslFree(zskiplist *zsl);
/*插入節(jié)點(diǎn)*/
zskiplistNode *zslInsert(zskiplist *zsl, unsigned long score, handler_pt func);
/*刪除頭節(jié)點(diǎn)*/
void zsklDeleteHead(zskiplist *zsl);
/*刪除任意節(jié)點(diǎn)*/
void zslDelete(zskiplist *zsl, zskplistNode *zn);
/*打印,調(diào)試*/
void zslPrint(zskiplist *zsl);

定時(shí)器接口實(shí)現(xiàn)

主要介紹四個(gè)接口實(shí)現(xiàn):初始化定時(shí)器,添加定時(shí)任務(wù),刪除/取消定時(shí)任務(wù),處理定時(shí)任務(wù)

// test_user.c  封裝給用戶使用的接口
static uint32_t
current_time() {
 uint32_t t;
    struct timespec ti;
    clock_getttime(CLOCK_MONOTONIC, &ti);
    t = (uint32_t)ti.tv_sec * 1000;
    t += ti.tv_sec / 1000000;
}
zskiplist *init_timer() {
    // 初始化定時(shí)器
    return zslCreate();
}
zskiplistNode *add_timer(zskiplist *zsl, uint32_t msec, handler_pt func) {
    // 添加定時(shí)任務(wù)
    msec += current_time();
    return zslInsert(zsl, msec, func);
}
void cancel_timer(zskiplist *zsl, zskiplistNode *zn) {
    // 刪除/取消定時(shí)任務(wù)
    zslDelete(zsl, zn);
}
void expire_timer(zskiplist *zsl){
    // 處理定時(shí)任務(wù)
    zskiplistNode *x;
    uint32_t now = current_time();
    for (;;) {
        x = zslMin(zsl);  // 最近節(jié)點(diǎn)
        if (!x) break;
        if (x->score > now)  break;  // 時(shí)間未到
        x->handler(x);  // 執(zhí)行相關(guān)定時(shí)任務(wù)
        zslDeleteHead(zsl);  // 執(zhí)行完刪除
    }
}

紅黑樹(shù)實(shí)現(xiàn)定時(shí)器

紅黑樹(shù)

紅黑樹(shù)是一種自平衡的二叉查找樹(shù),即,插入和刪除操作如果破壞樹(shù)的平衡時(shí),需要重新調(diào)整達(dá)到平衡狀態(tài)。因此,是一種比較難的數(shù)據(jù)結(jié)構(gòu)。

紅黑樹(shù)五條性質(zhì)

  • 每個(gè)節(jié)點(diǎn)要么是紅色,要么是黑色
  • 根節(jié)點(diǎn)是黑色
  • 每個(gè)葉子結(jié)點(diǎn)是黑色
  • 每個(gè)紅節(jié)點(diǎn)的兩個(gè)子節(jié)點(diǎn)一定是黑色
  • 任意一節(jié)點(diǎn)到每個(gè)葉子節(jié)點(diǎn)的路徑都含相同數(shù)目的黑結(jié)點(diǎn)

弄懂紅黑樹(shù)如何調(diào)整樹(shù)的平衡,保證滿足這5條性質(zhì),是比較麻煩,需要耐心的去推導(dǎo)一遍,此處不展開(kāi)。

紅黑樹(shù)實(shí)現(xiàn)定時(shí)器

AVL 樹(shù)平衡要求太高,維護(hù)平衡操作過(guò)多,較復(fù)雜;紅黑樹(shù)只需維護(hù)一個(gè)黑高度,效率較高

紅黑樹(shù)查找,刪除,添加時(shí)間復(fù)雜度為:O(log(n))

吸取開(kāi)源框架中優(yōu)秀數(shù)據(jù)結(jié)構(gòu)和代碼思想,選用nginx中的紅黑樹(shù)結(jié)構(gòu)

紅黑樹(shù)數(shù)據(jù)結(jié)構(gòu)

紅黑樹(shù)節(jié)點(diǎn)與紅黑樹(shù)

// rbtree.h  紅黑樹(shù)數(shù)據(jù)結(jié)構(gòu)以及相關(guān)接口,具體接口實(shí)現(xiàn)同上
#ifndef _NGX_RBTREE_H_INCLUDE_
#define _NGX_RBTREE_H_INCLUDE_

typedef unsigned int ngx_rbtree_key_t;
typedef unsigned int ngx_uint_t;
typedef int ngx_rbtree_key_int_t;

// 紅黑樹(shù)節(jié)點(diǎn)
typedef struct ngx_rbtree_node_s  ngx_rbtree_node_t;
struct ngx_rbtree_node_s {
    ngx_rbtree_key_t key;
    ngx_rbtree_node_t *left;
    ngx_rbtree_node_t *right;
    ngx_rbtree_node_t *parent;
    u_char    color;  // 節(jié)點(diǎn)顏色
    u_char    data;  // 節(jié)點(diǎn)數(shù)據(jù)
};
// 插入函數(shù)指針
typedef void (*ngx_rbtree_insert_pt) (ngx_rbtree_node_t *root,
     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
// 紅黑樹(shù)
typedef struct ngx_rbtree_s ngx_rbtree_t;
struct ngx_rbtree_s {
    ngx_rbtree_node_t  *root;
    ngx_rbtree_node_t  *sentinel;
    ngx_rbtree_insert_pt insert;
};

紅黑樹(shù)接口聲明

// 紅黑樹(shù)初始化
#define ngx_rbtree_init(tree, s, i)       \\
 ngx_rbtree_sentinel_init(s);      \\
 (tree)->root = s;        \\
 (tree)->sentinel = s;       \\
 (tree)->insert = i;        
// 插入操作
void ngx_rbtree_insert(ngx_rbtree_t *tree, ngx_rbtree_node_t *node);
// 刪除操作
void ngx_rbtree_delete(ngx_rbtree_t *tree, ngx_rbtree_node_t *node);
// 插入value
void ngx_rbtree_insert_value(ngx_rbtree_node_t *root, ngx_rbtree_node_t *node,
                            ngx_rbtree_node_t *sentinel);
// 插入timer
void ngx_rbtree_insert_timer_value(ngx_rbtree_node_t *root,
                                  ngx_rbtree_node_t *node,
                                  ngx_rbtree_node_t *sentinel);
// 獲取下一個(gè)節(jié)點(diǎn)
ngx_rbtree_node_t *ngx_rbtree_next(ngx_rbtree_t *tree, ngx_rbtree_node_t *node);
#define ngx_rbt_red(node)    ((node)->color = 1)
#define ngx_rbt_black(node)    ((node)->color = 0)
#define ngx_rbt_is_red(node)   ((node)->color)
#define ngx_rbt_is_black(node)   (!ngx_rbt_is_red(node))
#define ngx_rbt_copy_color(n1, n2)  (n1->color = n2->color)
#define ngx_rbtree_sentinel_init(node)  ngx_rbt_black(node)
// 找到最小值,一直往左走即可
static inline ngx_rbtree_node_t *
ngx_rbtree_min(ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
{
    while (node->left != sentinel){
        node = node->left;
    }
    return node;
}

定時(shí)器接口實(shí)現(xiàn)

// test_user.c  封裝給用戶使用的接口
ngx_rbtree_t     timer;
static ngx_rbtree_node_t   sentinel;
typedef struct timer_entry_s timer_entry_t;
typedef void (*timer_handler_pt)(timer_entry_t *ev);

struct timer_entry_s {
   ngx_rbtree_node_t timer;
    timer_handler_pt  handler;
};
// 初始化
int init_timer() {
    ngx_rbtree_init(&timer, &sentinel, ngx_rbtree_insert_timer_value);
    return 0;
}
// 添加定時(shí)任務(wù)
void add_timer(timer_entry_t *te, uint32_t msec) {
    msec += current_time();
    te->timer.key = msec;
    ngx_rbtree_insert(&timer, &te->timer);
}
// 取消定時(shí)
void cancel_timer(timer_entry_t *te) {
    ngx_rbtree_delete(&timer, &te->timer);
}
// 執(zhí)行到期任務(wù)
void expire_timer() {
    timer_entry_t *te;
    ngx_rbtree_node_t *sentinel, *root, *node;
    sentinel = timer.sentinel;
    uint32_t now = current_time();
    for(;;){
        root = timer.root;
        if (root == sentinel) break;
        if (node->key > now) break;
        te = (timer_entry_t *) ((char *) node - offsetof(timer_entry_t, timer));
        te->handler(te);
        ngx_rbtree_delete(&timer, &te->timer);
        free(te);
    }
}

以上,為紅黑樹(shù)和跳表實(shí)現(xiàn)的定時(shí)器,多線程環(huán)境下加鎖粒度比較大,高并發(fā)場(chǎng)景下效率不高,而時(shí)間輪適合高并發(fā)場(chǎng)景,如下。

時(shí)間輪實(shí)現(xiàn)定時(shí)器

時(shí)間輪

可以用于高效的執(zhí)行大量定時(shí)任務(wù),如下為分層時(shí)間輪示意圖:

圖片

timewheel

時(shí)間輪可參考時(shí)鐘進(jìn)行理解,秒針(Seconds wheel)轉(zhuǎn)一圈,則分針(Minutes wheel)走一格,分針(Minutes wheel)轉(zhuǎn)一圈,則時(shí)針(Hours wheel)走一格。隨著,時(shí)間的流逝,任務(wù)不斷從上層流下下一層,最終到達(dá)秒針輪上,當(dāng)秒針走到時(shí)執(zhí)行。

如上所示,時(shí)間輪大小為8格,秒針1s轉(zhuǎn)動(dòng)一格,其每一格所指向的鏈表保存著待執(zhí)行任務(wù)。比如,如果當(dāng)前指針指向1,要添加一個(gè)3s后執(zhí)行的任務(wù),由于1+3=4,即在第4格的鏈表中添加一個(gè)任務(wù)節(jié)點(diǎn)即可。如果要添加一個(gè)10s后執(zhí)行的任務(wù),10+1=11,超過(guò)了秒針輪范圍,因此需要對(duì)8取模11 % 8 = 3,即,會(huì)把這個(gè)任務(wù)放到分針輪上3對(duì)應(yīng)的鏈表上,之后再?gòu)姆轴樰啺讶蝿?wù)丟到秒針輪上進(jìn)行處理。也即,**秒針輪(Seconds wheel)**即保存著最近將要執(zhí)行的任務(wù),隨著時(shí)間的流逝,任務(wù)會(huì)慢慢的從上層流到秒針輪中進(jìn)行執(zhí)行。

優(yōu)點(diǎn):加鎖粒度較小,只需要加一個(gè)格子即可,一個(gè)格子對(duì)應(yīng)一串鏈表;適合高并發(fā)場(chǎng)景

缺點(diǎn):不好刪除

如何解決時(shí)間輪定時(shí)任務(wù)刪除?

  1. 通過(guò)引用計(jì)數(shù)來(lái)解決
  2. 交由業(yè)務(wù)層處理,將刪除標(biāo)記設(shè)為true , 在函數(shù)回調(diào)中根據(jù)這個(gè)標(biāo)記判斷是否需要處理

這里介紹兩種定時(shí)器實(shí)現(xiàn)方案,一種是簡(jiǎn)單實(shí)現(xiàn)方案,另一種是skynet較為復(fù)雜的實(shí)現(xiàn)。

時(shí)間輪實(shí)現(xiàn)定時(shí)器

簡(jiǎn)單時(shí)間輪實(shí)現(xiàn)方案

功能場(chǎng)景:由心跳包進(jìn)行超時(shí)連接檢測(cè),10s未收到則斷開(kāi)連接

一般做法:map每秒輪詢(xún)這個(gè)結(jié)構(gòu),檢測(cè)所有連接是否超時(shí),收到心跳包,記錄時(shí)間戳

缺點(diǎn):效率很差,每次需要檢測(cè)所有連接,時(shí)間復(fù)雜度為O(n)

優(yōu)化:分治大法,只需檢測(cè)快過(guò)期的連接, 采用hash數(shù)組+鏈表形式,數(shù)組大小設(shè)置成16 :[0] + [1] + [2] + ... + [15] ,相同過(guò)期時(shí)間的放入一個(gè)數(shù)組,因此,每次只需檢測(cè)最近過(guò)期的數(shù)組即可,不需要遍歷所有。

數(shù)據(jù)結(jié)構(gòu)定義

以下為定時(shí)器節(jié)點(diǎn),增加引用計(jì)數(shù)ref, 只有當(dāng)ref為0時(shí)刪除連接。

class CTimerNode {
public:
    CTimerNode(int fd) : id(fd), ref(0) {}
    void Offline() {this->ref = 0};
    bool tryKill() {
        if (this->ref == 0) return true;
        DecRef();
        if (this->ref == 0){
            return true;
        }
        return false;
    }
    void IncRef() {this->ref++;}
protected:
    void DecRef() {this->ref--;}
private:
    int ref;
    int id;
}
// 時(shí)間輪數(shù)組大小16, (x對(duì)16取余)==(x&1111) 落到0-15之間,即落到對(duì)應(yīng)的數(shù)組
const int TW_SIZE = 16;
const in EXPIRE = 10; // 過(guò)期間隔
const int TW_MASK = TW_SIZE - 1;  // 掩碼, 用于對(duì)16取余
static size_t iReadTick = 0;  // 滴答時(shí)鐘
typedef list
定時(shí)器接口
// 添加定時(shí)
void AddTimeOut(TimerWheel &tw, CTimerNode *p) {
    if (p) {
        p->IncRef();
        // 找到iRealTick對(duì)應(yīng)數(shù)組的idx(槽位)
        TimeList &le = tw[(iRealTick+EXPIRE) & TW_MASK];
        le.push_back(p);  // 把時(shí)間節(jié)點(diǎn)加入list中
    }
}
// 延時(shí)調(diào)用
void AddTimeOutDelay(TimeWheel &tw, CTimerNode *p, size_t delay) {
    if (p) {
        p->IncRef();
        TimeList &le = tw[(iRealTick + EXPIRE + delay) & TW_MASK];
        le.push_back(p);
    }
}
// 時(shí)間輪移動(dòng)
void TimerShift(TimeWheel &tw) {
    size_t tick = iRealTick;
    iRealTick++;
    TimeList &le = tw[tick & TW_MASK];
    TimeListIter iter = le.begin();
    for (; iter != le.end(); iter++) {
        CTimerNode *p = *iter;
        if (p && p->trySkill()){
            delete p;
        }
    }
    le.clear();
}
聲明:本文內(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

    文章

    11304

    瀏覽量

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

    關(guān)注

    23

    文章

    3248

    瀏覽量

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

    關(guān)注

    3

    文章

    573

    瀏覽量

    40132
收藏 人收藏

    評(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次下載

    定時(shí)器介紹

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

    詳細(xì)介紹定時(shí)器定時(shí)器中斷

    在測(cè)量控制系統(tǒng)中,常常需要實(shí)時(shí)時(shí)鐘,以實(shí)現(xiàn)定時(shí)控制、定時(shí)測(cè)量或定時(shí)中斷等。也常需要計(jì)數(shù)實(shí)現(xiàn)對(duì)
    的頭像 發(fā)表于 02-09 14:00 ?1.8w次閱讀
    詳細(xì)<b class='flag-5'>介紹</b><b class='flag-5'>定時(shí)器</b>和<b class='flag-5'>定時(shí)器</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í)器分類(lèi)基本定時(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>

    基于硬件定時(shí)器的軟件定時(shí)器

    出現(xiàn)使用軟件定時(shí)器的情況,但是講定時(shí)器需要從硬件定時(shí)器開(kāi)始講,軟件定時(shí)器是在其基礎(chǔ)之上延伸出來(lái)的。硬件定時(shí)器
    發(fā)表于 11-25 09:51 ?8次下載
    基于硬件<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)選取介紹2

    定時(shí)器在各種場(chǎng)景都需要用到,比如游戲的Buff實(shí)現(xiàn),Redis中的過(guò)期任務(wù),Linux中的定時(shí)任務(wù)等等。顧名思義,定時(shí)器的主要用途是執(zhí)行定時(shí)
    的頭像 發(fā)表于 04-21 15:20 ?1198次閱讀
    <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>2

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

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

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

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

    定時(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 ?534次閱讀
    <b class='flag-5'>定時(shí)器</b>的<b class='flag-5'>實(shí)現(xiàn)</b><b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>選擇