欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語言手寫多級時間輪定時器

 更新時間:2022年09月29日 09:16:28   作者:胡安民-獨行者  
這篇文章主要為大家詳細介紹了如何利用C語言實現(xiàn)手寫多級時間輪定時器,文中的示例代碼講解詳細,具有一定的借鑒價值,需要的可以參考一下

為什么使用多級時間輪的方式

有序隊列實現(xiàn)定時器

  • 添加/刪除任務(wù): 遍歷每一個節(jié)點, 找到相應(yīng)的位置插入, 因此時間復(fù)雜度為O(n)
  • 處理到期任務(wù): 取出最小定時任務(wù)為首節(jié)點, 因此時間復(fù)雜度為O(1)

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

有序隊列的性能瓶頸在于插入任務(wù)和刪除任務(wù)(查找排序),而樹形結(jié)構(gòu)能對其進行優(yōu)化

  • 添加/刪除/查找任務(wù): 紅黑樹能將排序的的時間復(fù)雜度降到O(log2N)
  • 處理到期任務(wù): 紅黑樹查找到最后過期的任務(wù)節(jié)點為最左側(cè)節(jié)點,因此時間復(fù)雜度為O(log2N)

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

  • 添加/查找任務(wù): 時間復(fù)雜度為O(log2N)
  • 刪除任務(wù): 時間復(fù)雜度為O(n), 可通過輔助數(shù)據(jù)結(jié)構(gòu)(map)來加快刪除操作
  • 處理到期任務(wù): 最小節(jié)點為根節(jié)點, 時間復(fù)雜度為O(1)

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

  • 添加/刪除/查找任務(wù): 時間復(fù)雜度為O(log2N)
  • 處理到期任務(wù): 最小節(jié)點為最左側(cè)節(jié)點, 時間復(fù)雜度為O(1), 但空間復(fù)雜度比較高, 為O(1.5n)

以上數(shù)據(jù)結(jié)構(gòu)之所以沒法做到O(1)的復(fù)雜度,究其原因是所有定時器節(jié)點掛在一條鏈表(或一棵樹)上。 總有那么一點缺陷但是在定時器要求精度高的場景下是不允許的

就比如0點1秒鐘需要執(zhí)行某個任務(wù),但是因為定時任務(wù)過多,需要一個一個遍歷對比時間,導(dǎo)致任務(wù)延期了

最好的解決辦法就是使用多級時間輪的方式,linux內(nèi)核使用的定時器就是這個算法, 講解多級時間輪前我們需要先了解單時間輪如何運作的

單級時間輪

單時間輪只有一個由bucket串起來的輪子,簡單來說就是一個數(shù)組而已,每一個index對應(yīng)一秒或者毫秒

假設(shè)從當前時刻0s開始計時,1s時定時器節(jié)點掛在bucket[1]下,2s時到期的定時器節(jié)點掛在bucket[2]下……

由于bucket是一個數(shù)組,能直接根據(jù)下標定位到具體定時器節(jié)點鏈,因此添加刪除節(jié)點、定時器到期執(zhí)行的時間復(fù)雜度均為O(1)。(有Hash內(nèi)味了)

但使用這個定時器所受的限制也顯而易見:待添加的timer到期時間必須在8s以內(nèi)。這顯然不能滿足實際需求。當然要擴展也很容易,直接增加bucket的個數(shù)就可以了。

如果按照正常需要最大的到期時間范圍要達到 2^32個(4294967296),如果采用上面這樣的單時間輪,我們就需要4294967296個 bucket這會帶來巨大的內(nèi)存消耗,顯然是需要優(yōu)化改進的。

改進的單時間輪其實是一個對時間和空間折中的思路,即不會像單時間輪那樣有O(1)的時間復(fù)雜度,但也不會像單時間輪那樣對bucket個數(shù)有巨大的需求。其原理也很簡單,就是重復(fù)轉(zhuǎn)圈,假設(shè)一圈60秒,那么有一個任務(wù)是在2分鐘后運行那么轉(zhuǎn)2圈就行,但是也會有問題

因為一圈就60個插槽,那么如果有100萬個任務(wù)呢,那么就導(dǎo)致每一個插槽都關(guān)聯(lián)一個很長的鏈表,每遍歷一個插槽都要遍歷當前插槽內(nèi)的所有任務(wù)判斷是否到期,那么這就蛻化為使用鏈表方式實現(xiàn)定時器了

rotation表示節(jié)點在時間輪轉(zhuǎn)了幾圈后才到期,當前時間指針指向某個bucket時,不能像簡單時間輪那樣直接對bucket下的所有節(jié)點執(zhí)行超時動作,而是需要對鏈表中節(jié)點遍歷一遍,判斷輪子轉(zhuǎn)動的次數(shù)是否等于節(jié)點中的rotation值,當兩者相等時,方可執(zhí)行超時操作。

上面所述的時間輪都是單槍匹馬戰(zhàn)斗的,因此很難在時間和空間上都達到理想效果。Linux所實現(xiàn)的多時間輪算法,借鑒了日常生活中水表的度量方法,通過低刻度走得快的輪子帶動高一級刻度輪子走動的方法,達到了僅使用較少刻度即可表示很大范圍度量值的效果。

多級時間輪

多級時間輪的算法很簡單就是創(chuàng)建多個單時間輪進行聯(lián)動,就如上圖3個時間輪,時分秒, 1天24小時那么就定義一個長度為24的數(shù)組,一個小數(shù)60分鐘那么就定義一個長度為60的數(shù)組,秒也一樣, 那么我們來說說怎么查找任務(wù)和執(zhí)行任務(wù)以及添加和刪除任務(wù)的,修改任務(wù)

添加任務(wù)

  • 先找到對應(yīng)的小時時間輪,然后依據(jù)任務(wù)的小時時間將任務(wù)插入到對應(yīng)的插槽里
  • 如果插槽里已有數(shù)據(jù)那么就使用鏈表的方式給鏈接起來

執(zhí)行任務(wù)

  • 規(guī)則是秒走一圈,分鐘走一格,分鐘走一圈,時鐘走一格
  • 系統(tǒng)運行時先計算初始時間,秒當前因該在第幾個插槽,分鐘當前在第幾個插槽…,然后從小時時間輪里開始看看當前插槽內(nèi)有沒有需要執(zhí)行的定時任務(wù)
  • 如果小時時間輪插槽內(nèi)有任務(wù)那么就將任務(wù)下發(fā)到分鐘,如果分鐘有任務(wù)那么就下發(fā)到秒鐘
  • 當秒時間輪執(zhí)行到有任務(wù)的插槽里,那么就創(chuàng)建一個線程執(zhí)行任務(wù)即可

刪除任務(wù)

  • 先在小時時間鐘里遍歷找到對應(yīng)的任務(wù),如果沒有那么到分鐘時間鐘里找…
  • 找到任務(wù)后刪除任務(wù)即可

修改和查詢都和刪除任務(wù)都是一個道理,先找到任務(wù)然后在進行操作

鎖的設(shè)計

執(zhí)行,添加,刪除,修改任務(wù)的時候都需要鎖住任務(wù)本身任務(wù)移交需要鎖住目標的插槽

描述全套過程:

此刻當前時間是02:59:01我有一個任務(wù)是03:00:02(上圖藍色方塊),然后我們只需要將任務(wù)存放在小時數(shù)組的第[3]個插槽里即可,之后進行初始化各個時間輪的指針小時[2],分鐘[59],秒[1],然后秒每走一圈,分鐘走一格,分鐘走一圈時鐘走一格,此刻時鐘[3]里有任務(wù),那么下發(fā)到分鐘里,分鐘[0]檢測到有任務(wù),那么下發(fā)到秒鐘[2]里,當秒走到[2]位置的時候發(fā)現(xiàn)有任務(wù),那么就創(chuàng)建一個線程進行執(zhí)行任務(wù)

下面我們就設(shè)計一個多級時間輪的定時器年,月,日,時,分,秒,毫秒(7層定時器)

注意: 不可能每毫秒都處理,不然壓力太大了,我們允許定時器誤差10毫秒左右,也就是10毫秒走一格,那么1000/10=100 ,也就是毫秒時間輪長度為100

還有就是定時器都要配套一種時間解析語言: 常用的有cron, 但是我使用的是我自己研發(fā)的c語言-自研定時器計劃任務(wù)語法

頭文件

#ifndef STUDY_TIMER_H
#define STUDY_TIMER_H
#include <pthread.h>
#include <unistd.h>
#include "../util/time_util.h"
#include "../structure/char_kv_list.h"
#include "thread_pool.h"
#include "../util/str_util.h"
#include "../util/timer_resolver.h"
#include <stdio.h>
#include <stdlib.h>
typedef struct timer_node {
    struct timer_node *next; //指向下一個節(jié)點
    long expires; //到期時間
    TimerResolver *timerResolver; //任務(wù)計劃解析后對象
    char   *strResolver; //保留任務(wù)計劃字符串,用于后期重新解析
    void * (*func)(void *); //回調(diào)函數(shù)
    void *args; //回調(diào)函數(shù)參數(shù)
    char *timer_id; //定時器名稱
    int timer_status; //定時器狀態(tài)(0:停止,1:啟動,2:待刪除,3確認刪除,4重啟任務(wù))
    int timer_dynamic; //0:等待執(zhí)行,1:執(zhí)行中 (用于展示任務(wù)的狀況)
    void * returnValue; //任務(wù)的返回值
} TimerNode;

//時間輪
typedef struct timer_wheel {
    int slot_num; //時間輪槽數(shù)量
    int type; //時間輪類型(0毫秒,1秒,2分,3時,4天,5月,6年)
    int slot_index; //時間輪槽索引
    CharKvList *slot_array; //時間輪插槽數(shù)組
    pthread_mutex_t *locks; //插槽鎖
} TimerWheel;

//7層時間輪
typedef struct timer {
    TimerWheel *wheel_millisecond; //1級時間輪 (毫秒)   1s = 1000ms=1000個槽,按照10毫秒一個槽,那么1s就有100個槽
    TimerWheel *wheel_second; //2級時間輪 (秒)     1m = 60s=60個槽,按照1秒一個槽,那么1m就有60個槽
    TimerWheel *wheel_minute; //3級時間輪 (分鐘)   1h = 60m=60個槽,按照1分鐘一個槽,那么1h就有60個槽
    TimerWheel *wheel_hour; //4級時間輪 (小時)   1d = 24h=24個槽,按照1小時一個槽,那么1d就有24個槽
    TimerWheel *wheel_day; //5級時間輪 (天)     1天=30個槽,按照1天一個槽,那么1月就有30個槽
    TimerWheel *wheel_month; //6級時間輪 (月)    1月=12個槽,按照1月一個槽,那么1年就有12個槽
    TimerWheel *wheel_year; //7級時間輪 (年)     年=10000個槽,按照1年一個槽,那么10000年就有10000個槽
    pthread_t  *threadIDs;   // 工作的線程IDs
    int busyNum;            // 忙的任務(wù)數(shù)量
    pthread_mutex_t thread_busyNum; //忙的任務(wù)數(shù)量線程ID
    int total;               // 總的任務(wù)數(shù)量
    pthread_mutex_t thread_total;  //總的任務(wù)數(shù)量線程ID
    ThreadPool *pool;       // 線程池
    CharKvList *tasks;      //全部的任務(wù)

} Timer;


typedef struct par_timer_Wheel{
    TimerWheel *wheel;
    Timer *timer;
} ParTimerWheel;
typedef struct par_timer_Node{
    TimerNode *timerNode;
    Timer *timer;
} ParTimerNode;


#define TIMER_STATUS_STOP 0 //未啟動
#define TIMER_STATUS_START 1 //已啟動
#define TIMER_STATUS_DEL 2 //待刪除 (不會刪除任務(wù),只是將任務(wù)狀態(tài)改為待刪除)
#define TIMER_STATUS_NOTARIZE_DEL 3 //確認刪除(會刪除任務(wù),通過外部因素來改變?nèi)蝿?wù)狀態(tài)進行刪除)
#define TIMER_STATUS_RESTART 4 //重啟任務(wù)(重置執(zhí)行計劃,然后將任務(wù)狀態(tài)改為已啟動,那么任務(wù)就會重新執(zhí)行)

#define TIMER_DYNAMIC_AWAIT 0  //等待執(zhí)行
#define TIMER_DYNAMIC_RUN 1   //執(zhí)行中


//毫秒級時間輪
#define WHEEL_MILLISECOND_SLOT_NUM 100 //1級時間輪 (毫秒)   1s = 1000ms=1000個槽,按照10毫秒一個槽,那么1s就有100個槽
//秒級時間輪
#define WHEEL_SECOND_SLOT_NUM 60 //2級時間輪 (秒)     1m = 60s=60個槽,按照1秒一個槽,那么1m就有60個槽
//分鐘級時間輪
#define WHEEL_MINUTE_SLOT_NUM 60 //3級時間輪 (分鐘)   1h = 60m=60個槽,按照1分鐘一個槽,那么1h就有60個槽
//小時級時間輪
#define WHEEL_HOUR_SLOT_NUM 24 //4級時間輪 (小時)   1d = 24h=24個槽,按照1小時一個槽,那么1d就有24個槽
//天級時間輪
#define WHEEL_DAY_SLOT_NUM 30 //5級時間輪 (天)     1天=30個槽,按照1天一個槽,那么1月就有30個槽
//月級時間輪
#define WHEEL_MONTH_SLOT_NUM 12 //6級時間輪 (月)     1月=12個槽,按照1月一個槽,那么1年就有12個槽
//年級時間輪
#define WHEEL_YEAR_SLOT_NUM 10000 //7級時間輪 (年)     年=10000個槽,按照1年一個槽,那么10000年就有10000個槽


Timer *create_timer(int maxSask);
void add_timer_sask(Timer *timer,char *timer_resolver,char *timer_name,void*(*func)(void *),void *args);
int getBusyNum( Timer *timer);
int getTotal( Timer *timer);
void updateTaskStatusDEL( Timer *timer,char *timer_id);
void updateTaskStatusRESTART( Timer *timer,char *timer_id);
void updateTaskStatusSTART( Timer *timer,char *timer_id);
void updateTaskTimerResolver( Timer *timer,char *timer_id,char * strResolver);
void updateTaskStatusSTOP( Timer *timer,char *timer_id);
#endif //STUDY_TIMER_H

實現(xiàn)文件

#include "timer.h"

static void *manager_millisecond(void *);
static void *manager_second_minute_hour_day_month_year(void *);
static  void *sask_manager( void *);

static void *sask_transfer(TimerWheel *,TimerWheel *);

static  void timer_node_sask_print(TimerNode *timerNode){
    char *string = format_time(timerNode->expires, "%Y-%m-%d %H:%M:%S");
    printf("%s任務(wù),預(yù)計執(zhí)行時間: %ld(時間戳)---%s(格式化時間)\n",timerNode->timer_id,timerNode->expires,string);
}

//創(chuàng)建參數(shù)
ParTimerWheel *create_par_timer_wheel(TimerWheel *timer_wheel, Timer *timer) {
    ParTimerWheel *wheel = (ParTimerWheel *) malloc(sizeof(ParTimerWheel));
    wheel->wheel = timer_wheel;
    wheel->timer = timer;
    return wheel;
}
//創(chuàng)建參數(shù)
ParTimerNode *create_par_timer_Node(Timer *timer, TimerNode *timerNode) {
    ParTimerNode *parTimerTimerNode = malloc(sizeof(ParTimerNode));
    parTimerTimerNode->timer = timer;
    parTimerTimerNode->timerNode = timerNode;
    return parTimerTimerNode;
}


//創(chuàng)建節(jié)點
TimerNode *create_timer_node(char *timerResolver, char *timer_id, void*(*func)(void *), void *args) {
    TimerNode *timerNode = (TimerNode *) malloc(sizeof(TimerNode));
    //解析定時計劃
    TimerResolver *timerResolver1 = create_timer_resolver(timerResolver);
    //獲取定時計劃執(zhí)行時間(10位時間戳(秒級))
    long expires = resolver(timerResolver1);
    //獲取計劃類型
    int type = get_plan_type(timerResolver1);
    int timer_status = type == 0 ? TIMER_STATUS_STOP : TIMER_STATUS_START;//如果是0那么是停止狀態(tài)
    timerNode->func = func;
    timerNode->args = args;
    timerNode->timerResolver = timerResolver1;
    timerNode->expires = expires;
    timerNode->timer_id = timer_id;
    timerNode->timer_status = timer_status;
    timerNode->timer_dynamic = TIMER_DYNAMIC_AWAIT; //默認等待執(zhí)行
    timerNode->next = NULL;
    timerNode->strResolver = timerResolver;//保存原始任務(wù)解析字符串

    timer_node_sask_print(timerNode);
    return timerNode;
}




//創(chuàng)建時間輪
TimerWheel *create_timer_wheel(int slot_num, int type) {
    TimerWheel *timerWheel = (TimerWheel *) malloc(sizeof(TimerWheel));
    timerWheel->slot_num = slot_num;
    timerWheel->slot_index = 0;
    timerWheel->type = type;
    timerWheel->locks = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t) * timerWheel->slot_num);
    //創(chuàng)建時間輪槽鎖
    for (int i = 0; i < timerWheel->slot_num; ++i) {
        pthread_mutex_init(&timerWheel->locks[i], NULL);
    }
    timerWheel->slot_array = createCharKvList(slot_num);
    //初始化所有槽為空
    for (int i = 0; i < timerWheel->slot_num; ++i) {
        addCharKvList(timerWheel->slot_array, NULL, NULL);
    }
    return timerWheel;
}

//創(chuàng)建定時器(最大可執(zhí)行任務(wù)數(shù)量為最大任務(wù)數(shù)*10超過了那么就可能導(dǎo)致崩潰,而最大任務(wù)數(shù)為代表同一時間能執(zhí)行的任務(wù))
Timer *create_timer(int maxSask) {
    Timer *timer = (Timer *) malloc(sizeof(Timer));
    timer->wheel_millisecond = create_timer_wheel(WHEEL_MILLISECOND_SLOT_NUM, 0);
    timer->wheel_second = create_timer_wheel(WHEEL_SECOND_SLOT_NUM, 1);
    timer->wheel_minute = create_timer_wheel(WHEEL_MINUTE_SLOT_NUM, 2);
    timer->wheel_hour = create_timer_wheel(WHEEL_HOUR_SLOT_NUM, 3);
    timer->wheel_day = create_timer_wheel(WHEEL_DAY_SLOT_NUM, 4);
    timer->wheel_month = create_timer_wheel(WHEEL_MONTH_SLOT_NUM, 5);
    timer->wheel_year = create_timer_wheel(WHEEL_YEAR_SLOT_NUM, 6);
    timer->tasks= createCharKvList(maxSask);
    timer->busyNum = 0;
    timer->thread_busyNum = (pthread_mutex_t ) malloc(sizeof(pthread_mutex_t) );
    timer->total = 0;
    timer->thread_total = (pthread_mutex_t ) malloc(sizeof(pthread_mutex_t));
    //創(chuàng)建線程池(最小線程數(shù)為160)
    int min = 10;
    timer->pool = threadPoolCreate(min, min + maxSask, maxSask * 10);
    timer->threadIDs = (pthread_t *) malloc(sizeof(pthread_t) * 3);
    pthread_create(&timer->threadIDs[0], NULL, manager_millisecond, timer);
    pthread_create(&timer->threadIDs[1], NULL, manager_second_minute_hour_day_month_year, timer);
    pthread_create(&timer->threadIDs[2], NULL, sask_manager, timer);
    return timer;
}

void addBusyNum( Timer *timer){
    //加鎖
    pthread_mutex_lock(&timer->thread_busyNum);
    timer->busyNum++;
    //解鎖
    pthread_mutex_unlock(&timer->thread_busyNum);
}

void subBusyNum( Timer *timer){
    //加鎖
    pthread_mutex_lock(&timer->thread_busyNum);
    timer->busyNum--;
    //解鎖
    pthread_mutex_unlock(&timer->thread_busyNum);
}

void addTotal( Timer *timer){
    //加鎖
    pthread_mutex_lock(&timer->thread_total);
    timer->total++;
    //解鎖
    pthread_mutex_unlock(&timer->thread_total);
}
void subTotal( Timer *timer){
    //加鎖
    pthread_mutex_lock(&timer->thread_total);
    timer->total--;
    //解鎖
    pthread_mutex_unlock(&timer->thread_total);
}

//獲取工作中的任務(wù)數(shù)量
int getBusyNum( Timer *timer){
    return timer->busyNum;
}
//總?cè)蝿?wù)數(shù)量
int getTotal( Timer *timer){
    return timer->total;
}
//修改任務(wù)狀態(tài),為確認刪除
void updateTaskStatusDEL( Timer *timer,char *timer_id){
    CharKvListData *pData = getCharKvListByKey(timer->tasks, timer_id);
    if(pData->data!=NULL){
        TimerNode *timerNode = (TimerNode *) pData->data;
        timerNode->timer_status = TIMER_STATUS_NOTARIZE_DEL;//修改為確認刪除
    }
}
//重啟任務(wù)(前提任務(wù)沒有被刪除)
void updateTaskStatusRESTART( Timer *timer,char *timer_id){
    CharKvListData *pData = getCharKvListByKey(timer->tasks, timer_id);
    if(pData->data!=NULL){
        TimerNode *timerNode = (TimerNode *) pData->data;
        if(timerNode->timer_status!=TIMER_STATUS_NOTARIZE_DEL){
            timerNode->timer_status = TIMER_STATUS_RESTART;//修改為重啟任務(wù)
        }
    }
}
//修改任務(wù)狀態(tài)為啟動(前提任務(wù)必須是暫停狀態(tài))
void updateTaskStatusSTART( Timer *timer,char *timer_id){
    CharKvListData *pData = getCharKvListByKey(timer->tasks, timer_id);
    if(pData->data!=NULL){
        TimerNode *timerNode = (TimerNode *) pData->data;
        if(timerNode->timer_status==TIMER_STATUS_STOP){
            timerNode->timer_status = TIMER_STATUS_START;//修改為啟動
        }
    }
}
//修改任務(wù)狀態(tài)為停止(前提任務(wù)不能是確認刪除)
void updateTaskStatusSTOP( Timer *timer,char *timer_id){
    CharKvListData *pData = getCharKvListByKey(timer->tasks, timer_id);
    if(pData->data!=NULL){
        TimerNode *timerNode = (TimerNode *) pData->data;
        if(timerNode->timer_status!=TIMER_STATUS_NOTARIZE_DEL){
            timerNode->timer_status = TIMER_STATUS_STOP;//修改為停止
        }
    }
}


//修改指定任務(wù)的執(zhí)行計劃并重啟任務(wù)
void updateTaskTimerResolver( Timer *timer,char *timer_id,char * strResolver){
    CharKvListData *pData = getCharKvListByKey(timer->tasks, timer_id);
    if(pData->data!=NULL){
        TimerNode *timerNode = (TimerNode *) pData->data;
        timerNode->strResolver = strResolver;
        timerNode->timer_status = TIMER_STATUS_RESTART;//修改為重啟任務(wù)
    }
}


//給指定時間輪添加任務(wù)
void add_timer_wheel_node(TimerWheel *wheel, TimerNode *timerNode) {
    if (timerNode == NULL) {
        return;
    }
    //獲取時間輪槽索引
    int slot_index = 0;
    switch (wheel->type) {
        case 0:
            slot_index = timerNode->expires % WHEEL_MILLISECOND_SLOT_NUM;
            break;
        case 1:
            slot_index = get_second(timerNode->expires);
            break;
        case 2:
            slot_index = get_minute(timerNode->expires);
            break;
        case 3:
            slot_index = get_hour(timerNode->expires);
            break;
        case 4:
            slot_index = get_day(timerNode->expires);
            break;
        case 5:
            slot_index = get_month(timerNode->expires);
            break;
        case 6:
            slot_index = get_year(timerNode->expires);
            break;
        default:
            printf("不存在的時間輪類型");
            exit(1);
    }
    //給目標時間輪槽位加鎖
    pthread_mutex_lock(&wheel->locks[slot_index]);
    //添加任務(wù)到目標時間輪槽位
    CharKvListData *pData = getCharKvList(wheel->slot_array, slot_index);
    if (pData->data == NULL) {//如果槽位是空的那么創(chuàng)建一個鏈表
        pData->data = timerNode;
    } else {//這個槽位已經(jīng)有任務(wù)了,我們需要把任務(wù)添加到鏈表中最后
        TimerNode *head = (TimerNode *) pData->data;
        TimerNode *pNode = (TimerNode *) pData->data;
        while (pNode != NULL) {
            head = pNode;
            if(str_equals(pNode->timer_id,timerNode->timer_id)){
                printf("%s任務(wù)名稱重復(fù)了,添加任務(wù)失敗",pNode->timer_id);
                return;
            }
            pNode = pNode->next;
        }
        head->next = timerNode;
    }
    //解鎖
    pthread_mutex_unlock(&wheel->locks[slot_index]);
}


//任務(wù)添加到時間輪
void add_timer_wheel(Timer *timer, TimerNode *timerNode) {
    //獲取執(zhí)行時間的年月日時分秒
    int sask_second = get_second(timerNode->expires);
    int sask_minute = get_minute(timerNode->expires);
    int sask_hour = get_hour(timerNode->expires);
    int sask_day = get_day(timerNode->expires);
    int sask_month = get_month(timerNode->expires);
    int sask_year = get_year(timerNode->expires);
    int current_second = get_current_second();
    int current_minute = get_current_minute();
    int current_hour = get_current_hour();
    int current_day = get_current_day();
    int current_month = get_current_month();
    int current_year = get_current_year();
    //將任務(wù)添加到對應(yīng)的時間輪中
    // 1.如果當前年大于等于任務(wù)的年
    if (current_year >= sask_year) {
        // 2.如果當前月大于等于任務(wù)的月
        if (current_month >= sask_month) {
            // 3.如果當前日大于等于任務(wù)的日
            if (current_day >= sask_day) {
                // 4.如果當前時大于等于任務(wù)的時
                if (current_hour >= sask_hour) {
                    // 5.如果當前分大于等于任務(wù)的分
                    if (current_minute >= sask_minute) {
                        // 6.如果當前秒大于等于任務(wù)的秒
                        if (current_second >= sask_second) {
                            add_timer_wheel_node(timer->wheel_millisecond, timerNode);
                        } else {
                            //添加到秒時間輪
                            add_timer_wheel_node(timer->wheel_second, timerNode);
                        }
                    } else {
                        //添加到分時間輪
                        add_timer_wheel_node(timer->wheel_minute, timerNode);
                    }
                } else {
                    //添加到時時間輪
                    add_timer_wheel_node(timer->wheel_hour, timerNode);
                }
            } else {
                //添加到天時間輪
                add_timer_wheel_node(timer->wheel_hour, timerNode);
            }
        } else {
            //添加到月時間輪
            add_timer_wheel_node(timer->wheel_month, timerNode);
        }
    } else {
        //添加到年時間輪
        add_timer_wheel_node(timer->wheel_year, timerNode);
    }
}

void add_timer_sask(Timer *timer, char *timer_resolver, char *timer_name, void*(*func)(void *), void *args) {
    //創(chuàng)建任務(wù)節(jié)點
    TimerNode *timerNode = create_timer_node(timer_resolver, timer_name, func, args);
    add_timer_wheel(timer, timerNode);//任務(wù)添加到時間輪
    addTotal(timer);//添加任務(wù)總數(shù)
    addCharKvList(timer->tasks, timerNode->timer_id, timerNode);//全部任務(wù)匯總
}

//根據(jù)當前的任務(wù)獲取下次執(zhí)行的任務(wù)
void next_timer_sask(TimerNode *timerNode) {
    //獲取定時計劃執(zhí)行時間(10位時間戳(秒級))
    long expires = resolver(timerNode->timerResolver);
    if (expires == 0) {
        timerNode->timer_status = TIMER_STATUS_DEL;//任務(wù)已經(jīng)執(zhí)行完畢
    }
    timerNode->expires = expires;
    timer_node_sask_print(timerNode);

}

//任務(wù)執(zhí)行
void thread_sask_run(void *args) {
    ParTimerNode *node = (ParTimerNode *) args;
    Timer *pTimer = node->timer;
    TimerNode *pNode = node->timerNode;
    addBusyNum(pTimer); //添加忙碌線程數(shù)
    pNode->timer_dynamic=TIMER_DYNAMIC_RUN;
    void *pVoid = pNode->func(pNode->args); //執(zhí)行任務(wù)
    pNode->returnValue=pVoid;
    pNode->timer_dynamic=TIMER_DYNAMIC_AWAIT;
    subBusyNum(pTimer);//減少忙碌線程數(shù)
    free(node);
}

static void manager_millisecond_sask(ParTimerWheel *parTimerTimerWheel) {

    Timer *pTimer = parTimerTimerWheel->timer;
    TimerWheel *pWheel = parTimerTimerWheel->wheel;
    //獲取當前時間
    long now = get_current_timestamp();
    //獲取當前插槽
    int slot_index = pWheel->slot_index;
    //獲取當前插槽的鎖
    pthread_mutex_t *lock = &pWheel->locks[slot_index];
    //加鎖
    pthread_mutex_lock(lock);
    //獲取當前插槽的鏈表
    CharKvList *list = pWheel->slot_array;
    //獲取當前插槽的節(jié)點
    CharKvListData *charKvListData = getCharKvList(list, slot_index);
    if (charKvListData->data != NULL) {
        //獲取當前插槽的鏈表,如果當前插槽的節(jié)點不為空,那么就執(zhí)行當前插槽的所有任務(wù)
        TimerNode *parent = charKvListData->data;
        TimerNode *node = charKvListData->data;
        while (node != NULL) {
            parent=node;
            //如果當前節(jié)點的過期時間小于當前時間,并且狀態(tài)是可執(zhí)行那么就執(zhí)行回調(diào)函數(shù)
            if (node->expires <= now && node->timer_status == TIMER_STATUS_START) {
                ParTimerNode *pNode = create_par_timer_Node(pTimer, node);
                //執(zhí)行回調(diào)函數(shù)
                threadPoolAdd(pTimer->pool,thread_sask_run, pNode);//添加任務(wù)到線程池
                //從新計算過期時間,并且判斷任務(wù)是否已經(jīng)執(zhí)行完畢,如果任務(wù)已經(jīng)執(zhí)行完畢,那么就不需要放入時間輪了
                next_timer_sask(node);
                if (node->timer_status != TIMER_STATUS_DEL) {
                    //添加任務(wù)到對應(yīng)的時間輪里
                    add_timer_wheel(pTimer, node);
                } else {
                    node->timer_status=TIMER_STATUS_DEL; //設(shè)置任務(wù)狀態(tài)為帶刪除
                    //移除鏈表中的任務(wù)
                    if(node->next==NULL) {
                        parent->next = NULL;
                        break; //跳出循環(huán)
                    }else{
                        parent->next=node->next;
                        node = parent->next;
                        continue;
                    }
                }
            }
            node = node->next;
        }
        //將當前插槽的節(jié)點設(shè)置為NULL
        charKvListData->data = NULL;
        charKvListData->key = NULL;
    }
    //解鎖
    pthread_mutex_unlock(lock);

}


//定時器管理-(毫秒)(如果插槽里有任務(wù)那么就會執(zhí)行插槽內(nèi)的所有任務(wù),而任務(wù)最多延遲1秒執(zhí)行)
static void *manager_millisecond(void *arg) {
    Timer *timer = (Timer *) arg;
    TimerWheel *pWheel = timer->wheel_millisecond;
    //初始化插槽獲取當前時間的毫秒數(shù)
    long millisecond = get_current_millisecond() / 10;
    pWheel->slot_index = millisecond;//設(shè)置當前插槽的索引
    ParTimerWheel *pTimerWheel = create_par_timer_wheel(pWheel, timer);
    //反復(fù)循環(huán)
    while (1) {
        //執(zhí)行時間輪的任務(wù)
        manager_millisecond_sask(pTimerWheel);
        //休眠10毫秒
        usleep(10000);
        //插槽索引+1
        pWheel->slot_index = pWheel->slot_index + 1;
        //如果插槽索引大于插槽數(shù)量那么就重置插槽索引
        if (pWheel->slot_index >= pWheel->slot_num) {
            pWheel->slot_index = 0;
        }
    }
}

static void *manager_second_minute_hour_day_month_year(void *arg) {
    Timer *timer = (Timer *) arg;
    TimerWheel *pWheel_millisecond = timer->wheel_millisecond;
    TimerWheel *pWheel_second = timer->wheel_second;
    TimerWheel *pWheel_minute = timer->wheel_minute;
    TimerWheel *pWheel_hour = timer->wheel_hour;
    TimerWheel *pWheel_day = timer->wheel_day;
    TimerWheel *pWheel_month = timer->wheel_month;
    TimerWheel *pWheel_year = timer->wheel_year;
    //初始化插槽獲取當前時間的秒數(shù)
    pWheel_second->slot_index = get_current_second();//設(shè)置當前插槽的索引
    pWheel_minute->slot_index = get_current_minute();//設(shè)置當前插槽的索引
    pWheel_hour->slot_index = get_current_hour();//設(shè)置當前插槽的索引
    pWheel_day->slot_index = get_current_day();//設(shè)置當前插槽的索引
    pWheel_month->slot_index = get_current_month();//設(shè)置當前插槽的索引
    pWheel_year->slot_index = get_current_year();//設(shè)置當前插槽的索引

    while (1) {
        int second = get_current_second();
        int minute = get_current_minute();
        int hour = get_current_hour();
        int day = get_current_day();
        int month = get_current_month();
        int year = get_current_year();
        if (pWheel_year->slot_index == year
            && pWheel_month->slot_index == month
            && pWheel_day->slot_index == day
            && pWheel_hour->slot_index == hour
            && pWheel_minute->slot_index == minute
            && pWheel_second->slot_index == second) {
            usleep(500000);// 休眠500毫秒
            continue;
        }

        int cu_pWheel_second = pWheel_second->slot_index;
        int cu_pWheel_minute = pWheel_minute->slot_index;
        int cu_pWheel_hour = pWheel_hour->slot_index;
        int cu_pWheel_day = pWheel_day->slot_index;
        int cu_pWheel_month = pWheel_month->slot_index;
        int cu_pWheel_year = pWheel_year->slot_index;

        pWheel_second->slot_index = second;
        pWheel_minute->slot_index = minute;
        pWheel_hour->slot_index = hour;
        pWheel_day->slot_index = day;
        pWheel_month->slot_index = month;
        pWheel_year->slot_index = year;

        if(pWheel_second->slot_index!=cu_pWheel_second){
            sask_transfer(pWheel_second,pWheel_millisecond);
//            printf("second===second:%d,minute:%d,hour:%d,day:%d,month:%d,year:%d\n", second, minute, hour, day, month, year);
        }
        if(pWheel_minute->slot_index!=cu_pWheel_minute){
            sask_transfer(pWheel_minute,pWheel_second);
        }
        if(pWheel_hour->slot_index!=cu_pWheel_hour){
            sask_transfer(pWheel_hour,pWheel_minute);
        }
        if(pWheel_day->slot_index!=cu_pWheel_day){
            sask_transfer(pWheel_day,pWheel_hour);
        }
        if(pWheel_month->slot_index!=cu_pWheel_month){
            sask_transfer(pWheel_month,pWheel_day);
        }
        if(pWheel_year->slot_index!=cu_pWheel_year){
            sask_transfer(pWheel_year,pWheel_month);
        }




    }
}

static void *sask_transfer(TimerWheel *pWheel,TimerWheel *nextWheel) {
    //判斷當前插槽是否有任務(wù),如果有任務(wù)那么就下發(fā)任務(wù)
    CharKvListData *pData = getCharKvList(pWheel->slot_array, pWheel->slot_index);
    if (pData->data != NULL) {
        //將任務(wù)下發(fā)
        add_timer_wheel_node(nextWheel, pData->data);
        //清除當前插槽的數(shù)據(jù)
        pData->data = NULL;
    }
}

//任務(wù)管理
static  void *sask_manager( void *args){
    Timer *timer=(Timer *)args;
    while (1){
        //迭代所有的任務(wù)
        CharKvListIterator *pIterator = createCharKvListIterator(timer->tasks);
        while (hasNextCharKvList(pIterator)) {
            CharKvListData *pData = nextCharKvList(pIterator);
            TimerNode *pNode = (TimerNode *) pData->data;
            if (pNode->timer_status == TIMER_STATUS_NOTARIZE_DEL) {//如果任務(wù)狀態(tài)為刪除狀態(tài)那么就刪除任務(wù)
                //刪除節(jié)點
                removeCharKvListByKey(timer->tasks, pNode->timer_id);
                free( pNode->timerResolver);//釋放定時計劃對象
                //釋放任務(wù)節(jié)點
                free(pNode);
                subTotal(timer);//減少總線任務(wù)數(shù)
                printf("=================刪除任務(wù):%s\n", pNode->timer_id);
            }else if(pNode->timer_status==TIMER_STATUS_RESTART){//重啟任務(wù)
                printf("=================%s:,任務(wù)重新加載\n", pNode->timer_id);
                //重新解析定時計劃
                TimerResolver *timerResolver1 = create_timer_resolver( pNode->strResolver);
                long expires = resolver(timerResolver1);
                pNode->timerResolver = timerResolver1;
                pNode->expires = expires;
                pNode->timer_status=TIMER_STATUS_START;//設(shè)置任務(wù)狀態(tài)為啟動
                timer_node_sask_print(pNode);//打印任務(wù)信息
                //將任務(wù)重新加入到對應(yīng)的時間輪中
                add_timer_wheel(timer, pNode);

            }
        }
        sleep(1);//休眠1秒檢測一次
    }
}

以上就是C語言手寫多級時間輪定時器的詳細內(nèi)容,更多關(guān)于C語言定時器的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C++計算ICMP頭的校驗和實例

    C++計算ICMP頭的校驗和實例

    這篇文章主要介紹了C++計算ICMP頭的校驗和的方法,代碼簡單實用,對于校驗ICMP報文來說有不錯的實用價值,需要的朋友可以參考下
    2014-10-10
  • C++實現(xiàn)并優(yōu)化異常系統(tǒng)

    C++實現(xiàn)并優(yōu)化異常系統(tǒng)

    異常處理是C++的一項語言機制,用于在程序中處理異常事件,下面這篇文章主要給大家介紹了關(guān)于C++中異常的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-08-08
  • QT實現(xiàn)定時關(guān)閉消息提示框

    QT實現(xiàn)定時關(guān)閉消息提示框

    這篇文章主要介紹了軟件利用Qt簡單實現(xiàn)消息提示框可定時自動關(guān)閉,文中的示例代碼講解詳細,對我們;了解QT有一定的幫助,感興趣的可以學習一下
    2022-01-01
  • C++實現(xiàn)動態(tài)分配const對象實例

    C++實現(xiàn)動態(tài)分配const對象實例

    這篇文章主要介紹了C++實現(xiàn)動態(tài)分配const對象實例,包括了const對象的創(chuàng)建、刪除及應(yīng)用實例,需要的朋友可以參考下
    2014-10-10
  • C語言庫函數(shù)qsort及bsearch快速排序算法使用解析

    C語言庫函數(shù)qsort及bsearch快速排序算法使用解析

    這篇文章主要為大家介紹了C語言庫函數(shù)qsort及bsearch快速排序算法的使用示例解析
    2022-02-02
  • 詳解C++中賦值和輸入輸出語句的用法

    詳解C++中賦值和輸入輸出語句的用法

    這篇文章主要介紹了詳解C++中賦值和輸入輸出語句的用法,是C++入門學習中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-09-09
  • C語言中獲取進程識別碼的相關(guān)函數(shù)

    C語言中獲取進程識別碼的相關(guān)函數(shù)

    這篇文章主要介紹了C語言中獲取進程識別碼的相關(guān)函數(shù),分別為getpid()函數(shù)和getppid()函數(shù)的使用,需要的朋友可以參考下
    2015-08-08
  • C++超詳細講解操作符的重載

    C++超詳細講解操作符的重載

    C++預(yù)定義中的運算符的操作對象只局限于基本的內(nèi)置數(shù)據(jù)類型,但是對于我們自定義的類型(類)是沒有辦法操作的。但是大多時候我們需要對我們定義的類型進行類似的運算,這個時候就需要我們對這么運算符進行重新定義,賦予其新的功能,以滿足自身的需求
    2022-06-06
  • c++難以發(fā)現(xiàn)的bug(有趣)

    c++難以發(fā)現(xiàn)的bug(有趣)

    這篇文章主要介紹了c++難以發(fā)現(xiàn)的bug(有趣)的相關(guān)資料,需要的朋友可以參考下
    2017-10-10
  • C++使用alsa庫實現(xiàn)播放聲音文件

    C++使用alsa庫實現(xiàn)播放聲音文件

    這篇文章主要為大家詳細介紹了Linux系統(tǒng)上C++如何使用alsa庫播放聲音文件,文中示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2024-04-04

最新評論