基于升序鏈表的定時器

#ifndef LST_TIMER
#define LST_TIMER


#include <time.h>


#define BUFFER_SIZE 64
class util_timer;
//用戶數據結構:客戶端地址、客戶端的socket、socket文件描述符、讀緩存和定時器
struct client_data
{
? ? sockaddr_in address;
? ? int sockfd;
? ? char buf[ BUFFER_SIZE ];
? ? util_timer* timer;
};


class util_timer
{
public:
? ? util_timer() : prev( NULL ), next( NULL ){}


public:
? ?time_t expire; //超時時間,使用絕對時間
? ?void (*cb_func)( client_data* );//任務回調
? ?client_data* user_data;//用戶數據
? ?util_timer* prev;//雙向鏈表,前一個定時器
? ?util_timer* next;//雙向鏈表,后一個定時器
};
//定時器鏈表,它是一個升序、雙向鏈表,且帶有頭結點和尾節點
class sort_timer_lst
{
public:
? ? sort_timer_lst() : head( NULL ), tail( NULL ) {}
? ? //釋放內存 ??
? ?~sort_timer_lst()
? ? {
? ? ? ? util_timer* tmp = head;
? ? ? ? while( tmp )
? ? ? ? {
? ? ? ? ? ? head = tmp->next;
? ? ? ? ? ? delete tmp;
? ? ? ? ? ? tmp = head;
? ? ? ? }
? ? }
//添加定時器
? ? void add_timer( util_timer* timer )
? ? {
? ? ? ? if( !timer )
? ? ? ? {
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? if( !head )
? ? ? ? {
? ? ? ? ? ? head = tail = timer;
? ? ? ? ? ? return;?
? ? ? ? }
//如果添加的定時器的時間比頭結點的時間要短,直接將其作為頭結點
? ? ? ? if( timer->expire < head->expire )
? ? ? ? {
? ? ? ? ? ? timer->next = head;
? ? ? ? ? ? head->prev = timer;
? ? ? ? ? ? head = timer;
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? add_timer( timer, head );
? ? }
//當某一個定時器發生變化時候,要調整對應定時器在鏈表中的位置
? ? void adjust_timer( util_timer* timer )
? ? {
? ? ? ? if( !timer )
? ? ? ? {
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? util_timer* tmp = timer->next;
//如果被調整的節點處于鏈表的尾部,或者新的超時值仍然小于其下一個定時器的超
//時值,則不需要調整

? ? ? ? if( !tmp || ( timer->expire < tmp->expire ) )
? ? ? ? {
? ? ? ? ? ? return;
? ? ? ? }
//如果定時器是頭部,則對該定時器從鏈表中去除并重新插入
? ? ? ? if( timer == head )
? ? ? ? {
? ? ? ? ? ? head = head->next;
? ? ? ? ? ? head->prev = NULL;
? ? ? ? ? ? timer->next = NULL;
? ? ? ? ? ? add_timer( timer, head );
? ? ? ? }
? ? ? ? else
? ? ? ? {
//如果目標定時器不是鏈表的頭結點,則將定時器從鏈表中去除,然后插入其原來的所在位置之后的部分鏈表
? ? ? ? ? ? timer->prev->next = timer->next;
? ? ? ? ? ? timer->next->prev = timer->prev;
? ? ? ? ? ? add_timer( timer, timer->next );
? ? ? ? }
? ? }
? ? void del_timer( util_timer* timer )
? ? {
? ? ? ? if( !timer )
? ? ? ? {
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? if( ( timer == head ) && ( timer == tail ) )
? ? ? ? {
? ? ? ? ? ? delete timer;
? ? ? ? ? ? head = NULL;
? ? ? ? ? ? tail = NULL;
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? if( timer == head )
? ? ? ? {
? ? ? ? ? ? head = head->next;
? ? ? ? ? ? head->prev = NULL;
? ? ? ? ? ? delete timer;
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? if( timer == tail )
? ? ? ? {
? ? ? ? ? ? tail = tail->prev;
? ? ? ? ? ? tail->next = NULL;
? ? ? ? ? ? delete timer;
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? timer->prev->next = timer->next;
? ? ? ? timer->next->prev = timer->prev;
? ? ? ? delete timer;
? ? }
//SIGARLM信號每一次被觸發就在其信號處理函數(如果是使用統一定位源,則是主函數)中執

//行一次tick函數以處理鏈表上到期的任務

//tick相當于一個心搏函數,每隔一段時間執行一次,以處理到期的任務

? ? void tick()
? ? {
? ? ? ? if( !head )
? ? ? ? {
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? printf( "timer tick\n" );
? ? ? ? time_t cur = time( NULL );//獲取系統當前時間
? ? ? ? util_timer* tmp = head;
//從頭結點開始依次處理每一個定時器,直到遇到一個尚未到期的定時器,
//這就是定時器的核心邏輯
? ? ? ? while( tmp )
? ? ? ? {
//使用的是絕對時間,因此將超時值與當前系統時間進行比較
? ? ? ? ? ? if( cur < tmp->expire )
? ? ? ? ? ? {
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? }
//調用定時器的回調函數
? ? ? ? ? ? tmp->cb_func( tmp->user_data );
//事件處理完畢之后就將其刪除
? ? ? ? ? ? head = tmp->next;
? ? ? ? ? ? if( head )
? ? ? ? ? ? {
? ? ? ? ? ? ? ? head->prev = NULL;
? ? ? ? ? ? }
? ? ? ? ? ? delete tmp;
? ? ? ? ? ? tmp = head;
? ? ? ? }
? ? }


private:
? ? void add_timer( util_timer* timer, util_timer* lst_head )
? ? {
? ? ? ? util_timer* prev = lst_head;
? ? ? ? util_timer* tmp = prev->next;
? ? ? ? while( tmp )
? ? ? ? {
? ? ? ? ? ? if( timer->expire < tmp->expire )
? ? ? ? ? ? {
? ? ? ? ? ? ? ? prev->next = timer;
? ? ? ? ? ? ? ? timer->next = tmp;
? ? ? ? ? ? ? ? tmp->prev = timer;
? ? ? ? ? ? ? ? timer->prev = prev;
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? }
? ? ? ? ? ? prev = tmp;
? ? ? ? ? ? tmp = tmp->next;
? ? ? ? }
? ? ? ? if( !tmp )
? ? ? ? {
? ? ? ? ? ? prev->next = timer;
? ? ? ? ? ? timer->prev = prev;
? ? ? ? ? ? timer->next = NULL;
? ? ? ? ? ? tail = timer;
? ? ? ? }
? ? ? ??
? ? }


private:
? ? util_timer* head;
? ? util_timer* tail;
};


#endif

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/385258.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/385258.shtml
英文地址,請注明出處:http://en.pswp.cn/news/385258.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

SIGCHLD信號使用和注意事項

1.SIGCHLD簡介 SIGCHILD是指在一個進程終止或者停止時&#xff0c;將SIGCHILD信號發送給其父進程&#xff0c;按照系統默認將忽略此信號&#xff0c;如果父進程希望被告知其子系統的這種狀態&#xff0c;則應捕捉此信號。注意&#xff1a;SIGCLD信號與其長得非常相似。SIGCLD是…

08-圖7 公路村村通 (30 分

現有村落間道路的統計數據表中&#xff0c;列出了有可能建設成標準公路的若干條道路的成本&#xff0c;求使每個村落都有公路連通所需要的最低成本。 輸入格式: 輸入數據包括城鎮數目正整數N&#xff08;≤&#xff09;和候選道路數目M&#xff08;≤&#xff09;&#xff1b;隨…

【Leetcode】33. 搜索旋轉排序數組

假設按照升序排序的數組在預先未知的某個點上進行了旋轉。 ( 例如&#xff0c;數組 [0,1,2,4,5,6,7] 可能變為 [4,5,6,7,0,1,2] )。 搜索一個給定的目標值&#xff0c;如果數組中存在這個目標值&#xff0c;則返回它的索引&#xff0c;否則返回 -1 。 你可以假設數組中不存在重…

08-圖9 關鍵活動 (30 分

假定一個工程項目由一組子任務構成&#xff0c;子任務之間有的可以并行執行&#xff0c;有的必須在完成了其它一些子任務后才能執行。“任務調度”包括一組子任務、以及每個子任務可以執行所依賴的子任務集。 比如完成一個專業的所有課程學習和畢業設計可以看成一個本科生要完成…

【Leetocde | 10 】54. 螺旋矩陣

解題代碼&#xff1a; class Solution { public:vector<int> spiralOrder(vector<vector<int>>& matrix) {if (matrix.empty() || matrix[0].empty()) return {};int m matrix.size(), n matrix[0].size();vector<int> res;int up 0, down m …

09-排序1 排序 (25 分)

給定N個&#xff08;長整型范圍內的&#xff09;整數&#xff0c;要求輸出從小到大排序后的結果。 本題旨在測試各種不同的排序算法在各種數據情況下的表現。各組測試數據特點如下&#xff1a; 數據1&#xff1a;只有1個元素&#xff1b; 數據2&#xff1a;11個不相同的整數…

網絡層

1. 簡單解釋一些ARP協議的工作過程

【Leetocde | 24 】152. 乘積最大子序列

這道題最直接的方法就是用DP來做&#xff0c;而且要用兩個dp數組&#xff0c;其中f[i]表示子數組[0, i]范圍內并且一定包含nums[i]數字的最大子數組乘積&#xff0c;g[i]表示子數組[0, i]范圍內并且一定包含nums[i]數字的最小子數組乘積&#xff0c;初始化時f[0]和g[0]都初始化…

【Leetcode | 1】3. 無重復字符的最長子串

這里我們可以建立一個HashMap&#xff0c;建立每個字符和其最后出現位置之間的映射&#xff0c;然后我們需要定義兩個變量res和left&#xff0c;其中res用來記錄最長無重復子串的長度&#xff0c;left指向該無重復子串左邊的起始位置的前一個&#xff0c;由于是前一個&#xff…

【Leetcode | 】93. 復原IP地址

class Solution { public:vector<string> strs;//用于存放臨時的四個段vector<string> result;//存放結果void dfs(string &s, int beginIndex, int step) {if (step 4 && beginIndex s.size()) //搜索成功{string temRec strs[0] "." …

海量數據(一)

1. 有1億個浮點數&#xff0c;如果找出期中最大的10000個&#xff1f; 最容易想到的方法是將數據全部排序&#xff0c;然后在排序后的集合中進行查找&#xff0c;最快的排序算法的時間復雜度一般為O&#xff08;nlogn&#xff09;&#xff0c;如快速排序。但是在32位的機器上&a…

1018 錘子剪刀布 (20 分)

大家應該都會玩“錘子剪刀布”的游戲&#xff1a;兩人同時給出手勢&#xff0c;勝負規則如圖所示&#xff1a; 現給出兩人的交鋒記錄&#xff0c;請統計雙方的勝、平、負次數&#xff0c;并且給出雙方分別出什么手勢的勝算最大。 輸入格式&#xff1a; 輸入第 1 行給出正整數 N…

1019 數字黑洞 (20 分)

給定任一個各位數字不完全相同的 4 位正整數&#xff0c;如果我們先把 4 個數字按非遞增排序&#xff0c;再按非遞減排序&#xff0c;然后用第 1 個數字減第 2 個數字&#xff0c;將得到一個新的數字。一直重復這樣做&#xff0c;我們很快會停在有“數字黑洞”之稱的 6174&…

61. 旋轉鏈表

給定一個鏈表&#xff0c;旋轉鏈表&#xff0c;將鏈表每個節點向右移動 k 個位置&#xff0c;其中 k 是非負數。 示例 1: 輸入: 1->2->3->4->5->NULL, k 2 輸出: 4->5->1->2->3->NULL 解釋: 向右旋轉 1 步: 5->1->2->3->4->NULL…

1020 月餅 (25 分)

月餅是中國人在中秋佳節時吃的一種傳統食品&#xff0c;不同地區有許多不同風味的月餅。現給定所有種類月餅的庫存量、總售價、以及市場的最大需求量&#xff0c;請你計算可以獲得的最大收益是多少。 注意&#xff1a;銷售時允許取出一部分庫存。樣例給出的情形是這樣的&#x…

2. 二叉樹的深度

題目描述 輸入一棵二叉樹&#xff0c;求該樹的深度。從根結點到葉結點依次經過的結點&#xff08;含根、葉結點&#xff09;形成樹的一條路徑&#xff0c;最長路徑的長度為樹的深度。 /* struct TreeNode {int val;struct TreeNode *left;struct TreeNode *right;TreeNode(in…

1021 個位數統計 (15 分

給定一個 k 位整數 1 (0, ,, d?k?1??>0)&#xff0c;請編寫程序統計每種不同的個位數字出現的次數。例如&#xff1a;給定 0&#xff0c;則有 2 個 0&#xff0c;3 個 1&#xff0c;和 1 個 3。 輸入格式&#xff1a; 每個輸入包含 1 個測試用例&#xff0c;即一個不超過…

【牛客網】X游戲

題目&#xff1a;X游戲 題目描述 我們稱一個數 X 為好數, 如果它的每位數字逐個地被旋轉 180 度后&#xff0c;我們仍可以得到一個有效的&#xff0c;且和 X 不同的數。要求每位數字都要被旋轉。 如果一個數的每位數字被旋轉以后仍然還是一個數字&#xff0c; 則這個數是有效…

1022 D進制的A+B (20 分)

輸入兩個非負 10 進制整數 A 和 B (≤)&#xff0c;輸出 AB 的 D (1)進制數。 輸入格式&#xff1a; 輸入在一行中依次給出 3 個整數 A、B 和 D。 輸出格式&#xff1a; 輸出 AB 的 D 進制數。 輸入樣例&#xff1a; 123 456 8輸出樣例&#xff1a; 1103 #include<cstdio>…

3. 二進制中1的個數

題目描述 輸入一個整數&#xff0c;輸出該數二進制表示中1的個數。其中負數用補碼表示。 class Solution { public:int NumberOf1(int n) {int count 0; for(int i 0; i < 32; i){if(n & (1 << i))count;}return count;} };