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

C語(yǔ)言手寫(xiě)多級(jí)時(shí)間輪定時(shí)器

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

為什么使用多級(jí)時(shí)間輪的方式

有序隊(duì)列實(shí)現(xiàn)定時(shí)器

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

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

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

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

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

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

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

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

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

就比如0點(diǎn)1秒鐘需要執(zhí)行某個(gè)任務(wù),但是因?yàn)槎〞r(shí)任務(wù)過(guò)多,需要一個(gè)一個(gè)遍歷對(duì)比時(shí)間,導(dǎo)致任務(wù)延期了

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

單級(jí)時(shí)間輪

單時(shí)間輪只有一個(gè)由bucket串起來(lái)的輪子,簡(jiǎn)單來(lái)說(shuō)就是一個(gè)數(shù)組而已,每一個(gè)index對(duì)應(yīng)一秒或者毫秒

假設(shè)從當(dāng)前時(shí)刻0s開(kāi)始計(jì)時(shí),1s時(shí)定時(shí)器節(jié)點(diǎn)掛在bucket[1]下,2s時(shí)到期的定時(shí)器節(jié)點(diǎn)掛在bucket[2]下……

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

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

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

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

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

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

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

多級(jí)時(shí)間輪

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

添加任務(wù)

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

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

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

刪除任務(wù)

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

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

鎖的設(shè)計(jì)

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

描述全套過(guò)程:

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

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

注意: 不可能每毫秒都處理,不然壓力太大了,我們?cè)试S定時(shí)器誤差10毫秒左右,也就是10毫秒走一格,那么1000/10=100 ,也就是毫秒時(shí)間輪長(zhǎng)度為100

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

頭文件

#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; //指向下一個(gè)節(jié)點(diǎn)
    long expires; //到期時(shí)間
    TimerResolver *timerResolver; //任務(wù)計(jì)劃解析后對(duì)象
    char   *strResolver; //保留任務(wù)計(jì)劃字符串,用于后期重新解析
    void * (*func)(void *); //回調(diào)函數(shù)
    void *args; //回調(diào)函數(shù)參數(shù)
    char *timer_id; //定時(shí)器名稱
    int timer_status; //定時(shí)器狀態(tài)(0:停止,1:啟動(dòng),2:待刪除,3確認(rèn)刪除,4重啟任務(wù))
    int timer_dynamic; //0:等待執(zhí)行,1:執(zhí)行中 (用于展示任務(wù)的狀況)
    void * returnValue; //任務(wù)的返回值
} TimerNode;

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

//7層時(shí)間輪
typedef struct timer {
    TimerWheel *wheel_millisecond; //1級(jí)時(shí)間輪 (毫秒)   1s = 1000ms=1000個(gè)槽,按照10毫秒一個(gè)槽,那么1s就有100個(gè)槽
    TimerWheel *wheel_second; //2級(jí)時(shí)間輪 (秒)     1m = 60s=60個(gè)槽,按照1秒一個(gè)槽,那么1m就有60個(gè)槽
    TimerWheel *wheel_minute; //3級(jí)時(shí)間輪 (分鐘)   1h = 60m=60個(gè)槽,按照1分鐘一個(gè)槽,那么1h就有60個(gè)槽
    TimerWheel *wheel_hour; //4級(jí)時(shí)間輪 (小時(shí))   1d = 24h=24個(gè)槽,按照1小時(shí)一個(gè)槽,那么1d就有24個(gè)槽
    TimerWheel *wheel_day; //5級(jí)時(shí)間輪 (天)     1天=30個(gè)槽,按照1天一個(gè)槽,那么1月就有30個(gè)槽
    TimerWheel *wheel_month; //6級(jí)時(shí)間輪 (月)    1月=12個(gè)槽,按照1月一個(gè)槽,那么1年就有12個(gè)槽
    TimerWheel *wheel_year; //7級(jí)時(shí)間輪 (年)     年=10000個(gè)槽,按照1年一個(gè)槽,那么10000年就有10000個(gè)槽
    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 //未啟動(dòng)
#define TIMER_STATUS_START 1 //已啟動(dòng)
#define TIMER_STATUS_DEL 2 //待刪除 (不會(huì)刪除任務(wù),只是將任務(wù)狀態(tài)改為待刪除)
#define TIMER_STATUS_NOTARIZE_DEL 3 //確認(rèn)刪除(會(huì)刪除任務(wù),通過(guò)外部因素來(lái)改變?nèi)蝿?wù)狀態(tài)進(jìn)行刪除)
#define TIMER_STATUS_RESTART 4 //重啟任務(wù)(重置執(zhí)行計(jì)劃,然后將任務(wù)狀態(tài)改為已啟動(dòng),那么任務(wù)就會(huì)重新執(zhí)行)

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


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


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

實(shí)現(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ù)計(jì)執(zhí)行時(shí)間: %ld(時(shí)間戳)---%s(格式化時(shí)間)\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é)點(diǎn)
TimerNode *create_timer_node(char *timerResolver, char *timer_id, void*(*func)(void *), void *args) {
    TimerNode *timerNode = (TimerNode *) malloc(sizeof(TimerNode));
    //解析定時(shí)計(jì)劃
    TimerResolver *timerResolver1 = create_timer_resolver(timerResolver);
    //獲取定時(shí)計(jì)劃執(zhí)行時(shí)間(10位時(shí)間戳(秒級(jí)))
    long expires = resolver(timerResolver1);
    //獲取計(jì)劃類型
    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)建時(shí)間輪
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)建時(shí)間輪槽鎖
    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)建定時(shí)器(最大可執(zhí)行任務(wù)數(shù)量為最大任務(wù)數(shù)*10超過(guò)了那么就可能導(dǎo)致崩潰,而最大任務(wù)數(shù)為代表同一時(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ù)沒(méi)有被刪除)
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)為啟動(dòng)(前提任務(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;//修改為啟動(dòng)
        }
    }
}
//修改任務(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í)行計(jì)劃并重啟任務(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ù)
    }
}


//給指定時(shí)間輪添加任務(wù)
void add_timer_wheel_node(TimerWheel *wheel, TimerNode *timerNode) {
    if (timerNode == NULL) {
        return;
    }
    //獲取時(shí)間輪槽索引
    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("不存在的時(shí)間輪類型");
            exit(1);
    }
    //給目標(biāo)時(shí)間輪槽位加鎖
    pthread_mutex_lock(&wheel->locks[slot_index]);
    //添加任務(wù)到目標(biāo)時(shí)間輪槽位
    CharKvListData *pData = getCharKvList(wheel->slot_array, slot_index);
    if (pData->data == NULL) {//如果槽位是空的那么創(chuàng)建一個(gè)鏈表
        pData->data = timerNode;
    } else {//這個(gè)槽位已經(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ù)添加到時(shí)間輪
void add_timer_wheel(Timer *timer, TimerNode *timerNode) {
    //獲取執(zhí)行時(shí)間的年月日時(shí)分秒
    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ù)添加到對(duì)應(yīng)的時(shí)間輪中
    // 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)前時(shí)大于等于任務(wù)的時(shí)
                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 {
                            //添加到秒時(shí)間輪
                            add_timer_wheel_node(timer->wheel_second, timerNode);
                        }
                    } else {
                        //添加到分時(shí)間輪
                        add_timer_wheel_node(timer->wheel_minute, timerNode);
                    }
                } else {
                    //添加到時(shí)時(shí)間輪
                    add_timer_wheel_node(timer->wheel_hour, timerNode);
                }
            } else {
                //添加到天時(shí)間輪
                add_timer_wheel_node(timer->wheel_hour, timerNode);
            }
        } else {
            //添加到月時(shí)間輪
            add_timer_wheel_node(timer->wheel_month, timerNode);
        }
    } else {
        //添加到年時(shí)間輪
        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é)點(diǎn)
    TimerNode *timerNode = create_timer_node(timer_resolver, timer_name, func, args);
    add_timer_wheel(timer, timerNode);//任務(wù)添加到時(shí)間輪
    addTotal(timer);//添加任務(wù)總數(shù)
    addCharKvList(timer->tasks, timerNode->timer_id, timerNode);//全部任務(wù)匯總
}

//根據(jù)當(dāng)前的任務(wù)獲取下次執(zhí)行的任務(wù)
void next_timer_sask(TimerNode *timerNode) {
    //獲取定時(shí)計(jì)劃執(zhí)行時(shí)間(10位時(shí)間戳(秒級(jí)))
    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)前時(shí)間
    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é)點(diǎn)
    CharKvListData *charKvListData = getCharKvList(list, slot_index);
    if (charKvListData->data != NULL) {
        //獲取當(dāng)前插槽的鏈表,如果當(dāng)前插槽的節(jié)點(diǎn)不為空,那么就執(zhí)行當(dāng)前插槽的所有任務(wù)
        TimerNode *parent = charKvListData->data;
        TimerNode *node = charKvListData->data;
        while (node != NULL) {
            parent=node;
            //如果當(dāng)前節(jié)點(diǎn)的過(guò)期時(shí)間小于當(dāng)前時(shí)間,并且狀態(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ù)到線程池
                //從新計(jì)算過(guò)期時(shí)間,并且判斷任務(wù)是否已經(jīng)執(zhí)行完畢,如果任務(wù)已經(jīng)執(zhí)行完畢,那么就不需要放入時(shí)間輪了
                next_timer_sask(node);
                if (node->timer_status != TIMER_STATUS_DEL) {
                    //添加任務(wù)到對(duì)應(yīng)的時(shí)間輪里
                    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é)點(diǎn)設(shè)置為NULL
        charKvListData->data = NULL;
        charKvListData->key = NULL;
    }
    //解鎖
    pthread_mutex_unlock(lock);

}


//定時(shí)器管理-(毫秒)(如果插槽里有任務(wù)那么就會(huì)執(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í)間的毫秒數(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í)行時(shí)間輪的任務(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í)間的秒數(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é)點(diǎn)
                removeCharKvListByKey(timer->tasks, pNode->timer_id);
                free( pNode->timerResolver);//釋放定時(shí)計(jì)劃對(duì)象
                //釋放任務(wù)節(jié)點(diǎn)
                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);
                //重新解析定時(shí)計(jì)劃
                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)為啟動(dòng)
                timer_node_sask_print(pNode);//打印任務(wù)信息
                //將任務(wù)重新加入到對(duì)應(yīng)的時(shí)間輪中
                add_timer_wheel(timer, pNode);

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

以上就是C語(yǔ)言手寫(xiě)多級(jí)時(shí)間輪定時(shí)器的詳細(xì)內(nèi)容,更多關(guān)于C語(yǔ)言定時(shí)器的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C++計(jì)算ICMP頭的校驗(yàn)和實(shí)例

    C++計(jì)算ICMP頭的校驗(yàn)和實(shí)例

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

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

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

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

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

    C++實(shí)現(xiàn)動(dòng)態(tài)分配const對(duì)象實(shí)例

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

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

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

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

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

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

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

    C++超詳細(xì)講解操作符的重載

    C++預(yù)定義中的運(yùn)算符的操作對(duì)象只局限于基本的內(nèi)置數(shù)據(jù)類型,但是對(duì)于我們自定義的類型(類)是沒(méi)有辦法操作的。但是大多時(shí)候我們需要對(duì)我們定義的類型進(jìn)行類似的運(yùn)算,這個(gè)時(shí)候就需要我們對(duì)這么運(yùn)算符進(jìn)行重新定義,賦予其新的功能,以滿足自身的需求
    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庫(kù)實(shí)現(xiàn)播放聲音文件

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

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

最新評(píng)論