C語言手寫多級時間輪定時器
為什么使用多級時間輪的方式

有序隊列實現(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è)從當(dāng)前時刻0s開始計時,1s時定時器節(jié)點掛在bucket[1]下,2s時到期的定時器節(jié)點掛在bucket[2]下……
由于bucket是一個數(shù)組,能直接根據(jù)下標(biāo)定位到具體定時器節(jié)點鏈,因此添加刪除節(jié)點、定時器到期執(zhí)行的時間復(fù)雜度均為O(1)。(有Hash內(nèi)味了)
但使用這個定時器所受的限制也顯而易見:待添加的timer到期時間必須在8s以內(nèi)。這顯然不能滿足實際需求。當(dāng)然要擴展也很容易,直接增加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)一個很長的鏈表,每遍歷一個插槽都要遍歷當(dāng)前插槽內(nèi)的所有任務(wù)判斷是否到期,那么這就蛻化為使用鏈表方式實現(xiàn)定時器了

rotation表示節(jié)點在時間輪轉(zhuǎn)了幾圈后才到期,當(dāng)前時間指針指向某個bucket時,不能像簡單時間輪那樣直接對bucket下的所有節(jié)點執(zhí)行超時動作,而是需要對鏈表中節(jié)點遍歷一遍,判斷輪子轉(zhuǎn)動的次數(shù)是否等于節(jié)點中的rotation值,當(dāng)兩者相等時,方可執(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)運行時先計算初始時間,秒當(dāng)前因該在第幾個插槽,分鐘當(dāng)前在第幾個插槽…,然后從小時時間輪里開始看看當(dāng)前插槽內(nèi)有沒有需要執(zhí)行的定時任務(wù)
- 如果小時時間輪插槽內(nèi)有任務(wù)那么就將任務(wù)下發(fā)到分鐘,如果分鐘有任務(wù)那么就下發(fā)到秒鐘
- 當(dāng)秒時間輪執(zhí)行到有任務(wù)的插槽里,那么就創(chuàng)建一個線程執(zhí)行任務(wù)即可
刪除任務(wù)
- 先在小時時間鐘里遍歷找到對應(yīng)的任務(wù),如果沒有那么到分鐘時間鐘里找…
- 找到任務(wù)后刪除任務(wù)即可
修改和查詢都和刪除任務(wù)都是一個道理,先找到任務(wù)然后在進行操作
鎖的設(shè)計
執(zhí)行,添加,刪除,修改任務(wù)的時候都需要鎖住任務(wù)本身任務(wù)移交需要鎖住目標(biāo)的插槽
描述全套過程:
此刻當(dāng)前時間是02:59:01我有一個任務(wù)是03:00:02(上圖藍色方塊),然后我們只需要將任務(wù)存放在小時數(shù)組的第[3]個插槽里即可,之后進行初始化各個時間輪的指針小時[2],分鐘[59],秒[1],然后秒每走一圈,分鐘走一格,分鐘走一圈時鐘走一格,此刻時鐘[3]里有任務(wù),那么下發(fā)到分鐘里,分鐘[0]檢測到有任務(wù),那么下發(fā)到秒鐘[2]里,當(dāng)秒走到[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確認(rèn)刪除,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 //確認(rèn)刪除(會刪除任務(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那么是停止?fàn)顟B(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; //默認(rèn)等待執(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),為確認(rèn)刪除
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;//修改為確認(rèn)刪除
}
}
//重啟任務(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ù)不能是確認(rèn)刪除)
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);
}
//給目標(biāo)時間輪槽位加鎖
pthread_mutex_lock(&wheel->locks[slot_index]);
//添加任務(wù)到目標(biāo)時間輪槽位
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.如果當(dāng)前年大于等于任務(wù)的年
if (current_year >= sask_year) {
// 2.如果當(dāng)前月大于等于任務(wù)的月
if (current_month >= sask_month) {
// 3.如果當(dāng)前日大于等于任務(wù)的日
if (current_day >= sask_day) {
// 4.如果當(dāng)前時大于等于任務(wù)的時
if (current_hour >= sask_hour) {
// 5.如果當(dāng)前分大于等于任務(wù)的分
if (current_minute >= sask_minute) {
// 6.如果當(dāng)前秒大于等于任務(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ù)當(dāng)前的任務(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;
//獲取當(dāng)前時間
long now = get_current_timestamp();
//獲取當(dāng)前插槽
int slot_index = pWheel->slot_index;
//獲取當(dāng)前插槽的鎖
pthread_mutex_t *lock = &pWheel->locks[slot_index];
//加鎖
pthread_mutex_lock(lock);
//獲取當(dāng)前插槽的鏈表
CharKvList *list = pWheel->slot_array;
//獲取當(dāng)前插槽的節(jié)點
CharKvListData *charKvListData = getCharKvList(list, slot_index);
if (charKvListData->data != NULL) {
//獲取當(dāng)前插槽的鏈表,如果當(dāng)前插槽的節(jié)點不為空,那么就執(zhí)行當(dāng)前插槽的所有任務(wù)
TimerNode *parent = charKvListData->data;
TimerNode *node = charKvListData->data;
while (node != NULL) {
parent=node;
//如果當(dāng)前節(jié)點的過期時間小于當(dāng)前時間,并且狀態(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;
}
//將當(dāng)前插槽的節(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;
//初始化插槽獲取當(dāng)前時間的毫秒數(shù)
long millisecond = get_current_millisecond() / 10;
pWheel->slot_index = millisecond;//設(shè)置當(dāng)前插槽的索引
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;
//初始化插槽獲取當(dāng)前時間的秒數(shù)
pWheel_second->slot_index = get_current_second();//設(shè)置當(dāng)前插槽的索引
pWheel_minute->slot_index = get_current_minute();//設(shè)置當(dāng)前插槽的索引
pWheel_hour->slot_index = get_current_hour();//設(shè)置當(dāng)前插槽的索引
pWheel_day->slot_index = get_current_day();//設(shè)置當(dāng)前插槽的索引
pWheel_month->slot_index = get_current_month();//設(shè)置當(dāng)前插槽的索引
pWheel_year->slot_index = get_current_year();//設(shè)置當(dāng)前插槽的索引
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) {
//判斷當(dāng)前插槽是否有任務(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);
//清除當(dāng)前插槽的數(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語言庫函數(shù)qsort及bsearch快速排序算法使用解析
這篇文章主要為大家介紹了C語言庫函數(shù)qsort及bsearch快速排序算法的使用示例解析2022-02-02

