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è)從當前時刻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語言庫函數(shù)qsort及bsearch快速排序算法使用解析
這篇文章主要為大家介紹了C語言庫函數(shù)qsort及bsearch快速排序算法的使用示例解析2022-02-02