1. 程式人生 > >網路程式設計中最小堆實現的定時器

網路程式設計中最小堆實現的定時器

在開發Linux網路程式時,通常需要維護多個定時器,如維護客戶端心跳時間、檢查多個數據包的超時重傳等。如果採用Linux的SIGALARM訊號實現,則會帶來較大的系統開銷,且不便於管理。

本文在應用層實現了一個基於時間堆的高效能定時器,同時考慮到定時的粒度問題,由於通過alarm系統呼叫設定的SIGALARM訊號只能以秒為單位觸發,因此需要採用其它手段實現更細粒度的定時操作,當然,這裡不考慮使用多執行緒+sleep的實現方法,理由效能太低。

通常的做法還有采用基於升序的時間連結串列,但升序時間連結串列的插入操作效率較低,需要遍歷連結串列。因此本實現方案使用最小堆來維護多個定時器,插入O(logn)、刪除O(1)、查詢O(1)的效率較高。

首先是每個定時器的定義:

  1. class heap_timer  
  2. {  
  3. public:  
  4.     heap_timer( int ms_delay )  
  5.     {  
  6.         gettimeofday( &expire, NULL );  
  7.         expire.tv_usec += ms_delay * 1000;  
  8.         if ( expire.tv_usec > 1000000 )  
  9.         {  
  10.             expire.tv_sec += expire.tv_usec / 1000000;  
  11.             expire.tv_usec %= 1000000;  
  12.         }  
  13.     }  
  14. public:  
  15.     struct timeval expire;  
  16.     void (*cb_func)( client_data* );  
  17.     client_data* user_data;  
  18.     ~heap_timer()  
  19.     {  
  20.         delete user_data;  
  21.     }  
  22. };  

包括一個超時時間expire、超時回撥函式cb_func以及一個user_data變數,user_data用於儲存與定時器相關的使用者資料,使用者資料可以根據不同的應用場合進行修改,這裡實現的是一個智慧博物館的閘道器,閘道器接收來自zigbee協調器的使用者資料,併為每個使用者維護一段等待時間T,在T到來之前,同一個使用者的所有資料都存放到user_data的target_list中,當T到來時,根據target_list列表選擇一個適當的target併發送到ip_address,同時刪除定時器(有點扯遠了=。=)。總之,要實現的功能就是給每個使用者維護一個定時器,定時值到來時做一些操作。
  1. class client_data  
  2. {  
  3. public:  
  4.     client_data(char *address):target_count(0)  
  5.     {  
  6.         strcpy(ip_address,address);  
  7.     }  
  8. private:  
  9.     char ip_address[32];  
  10.     target target_list[64];  
  11.     int target_count;  
  12.     ......  
  13. };  

以下是時間堆的類定義,包括了一些基本的堆操作:插入、刪除、擴容,還包括了定時器溢位時的操作函式tick()

  1. class time_heap  
  2. {  
  3. public:  
  4.     time_heap( int cap  = 1) throw ( std::exception )  
  5.         : capacity( cap ), cur_size( 0 )  
  6.     {  
  7.         array = new heap_timer* [capacity];  
  8.         if ( ! array )  
  9.         {  
  10.             throw std::exception();  
  11.         }  
  12.         forint i = 0; i < capacity; ++i )  
  13.         {  
  14.             array[i] = NULL;  
  15.         }  
  16.     }  
  17.     ~time_heap()  
  18.     {  
  19.         for ( int i =  0; i < cur_size; ++i )  
  20.         {  
  21.             delete array[i];  
  22.         }  
  23.         delete [] array;  
  24.     }  
  25. public:  
  26.     int get_cursize()  
  27.     {  
  28.         return cur_size;  
  29.     }  
  30.     void add_timer( heap_timer* timer ) throw ( std::exception )  
  31.     {  
  32.         if( !timer )  
  33.         {  
  34.             return;  
  35.         }  
  36.         if( cur_size >= capacity )  
  37.         {  
  38.             resize();  
  39.         }  
  40.         int hole = cur_size++;  
  41.         int parent = 0;  
  42.         for( ; hole > 0; hole=parent )  
  43.         {  
  44.             parent = (hole-1)/2;  
  45.             if ( timercmp( &(array[parent]->expire), &(timer->expire), <= ) )  
  46.             {  
  47.                 break;  
  48.             }  
  49.             array[hole] = array[parent];  
  50.         }  
  51.         array[hole] = timer;  
  52.     }  
  53.     void del_timer( heap_timer* timer )  
  54.     {  
  55.         if( !timer )  
  56.         {  
  57.             return;  
  58.         }  
  59.         // lazy delelte
  60.         timer->cb_func = NULL;  
  61.     }  
  62.     int top(struct timeval &time_top) const
  63.     {  
  64.         if ( empty() )  
  65.         {  
  66.             return 0;  
  67.         }  
  68.         time_top = array[0]->expire;  
  69.         return 1;  
  70.     }  
  71.     void pop_timer()  
  72.     {  
  73.         if( empty() )  
  74.         {  
  75.             return;  
  76.         }  
  77.         if( array[0] )  
  78.         {  
  79.             delete array[0];  
  80.             array[0] = array[--cur_size];  
  81.             percolate_down( 0 );  
  82.         }  
  83.     }  
  84.     void tick()  
  85.     {  
  86.         heap_timer* tmp = array[0];  
  87.         struct timeval cur;  
  88.         gettimeofday( &cur, NULL );  
  89.         while( !empty() )  
  90.         {  
  91.             

    相關推薦

    網路程式設計實現定時

    在開發Linux網路程式時,通常需要維護多個定時器,如維護客戶端心跳時間、檢查多個數據包的超時重傳等。如果採用Linux的SIGALARM訊號實現,則會帶來較大的系統開銷,且不便於管理。 本文在應用層實現了一個基於時間堆的高效能定時器,同時考慮到定時的粒度問題,

    一個簡單定時實現demo

    #include <stdio.h> #include <stdlib.h> #include <sys/time.h> #include <time.h> #include <unistd.h> #

    【劍指offer】資料流位數(實現

    題目描述 如何得到一個數據流中的中位數?如果從資料流中讀出奇數個數值,那麼中位數就是所有數值排序之後位於中間的數值。如果從資料流中讀出偶數個數值,那麼中位數就是所有數值排序之後中間兩個數的平均值。我們使用Insert()方法讀取資料流,使用GetMedian()方法獲取當前讀取資料的中位

    實現

    題目 最小堆實現 解答 public class MinHeap { public static void main(String[] args) { int[] test = {23,42,5,1,56}; heapify(test

    實現哈夫曼樹的構造及哈夫曼編碼、解碼

          以下程式的演算法思想主要來自於浙江大學陳越老師主編的資料結構一書。最大堆(最小堆思想差不多)(之後會寫一篇部落格介紹),這裡主要講講哈夫曼樹的定義及實現。 Huffman Tree 相關概念: 結點的路徑長度:從根結點到該結點的路徑上分支的數

    運用並查集與實現Kruskal演算法

    前言 Kruskal是在一個圖(圖論)中生成最小生成樹的演算法之一。(另外還有Prim演算法,之後會涉及到)這就牽扯到了最小生成樹的概念,其實就是總權值最小的一個連通無迴路的子圖。(結合下文的示意圖不難理解)這裡的程式碼並沒有用圖的儲存結構(如:矩陣,鄰接連結

    演算法導論實現k路歸併

    問題:請給出一個時間為O(nlgk),用來將k個已排序連結串列合併為一個排序連結串列的演算法。此處的n為所有輸入連結串列中元素的總數。(提示:用一個最小堆來做k路合併) 程式設計思路: 假設k個連結串列都是非降序排列的。 (1)取k個元素建立最小堆,這k個元素分別是

    java實現優先權佇列和求大的n個數問題

    堆在實現優先權佇列和求最大最小的n個數問題上,有著莫大的優勢! 對於最大堆和最小堆的定義此處不再贅述,課參考網上文章:http://blog.csdn.net/genios/article/details/8157031 本文主要是對最小堆進行實現和應用,僅供新手參考。

    go利用實現優先佇列

    實現程式碼 package core import "container/heap" type Item struct { Value interface{} Index

    用鄰接表和實現Dijkstra 短路演算法 (Java實現

    演算法特點: 迪科斯徹演算法使用了廣度優先搜尋解決賦權有向圖或者無向圖的單源最短路徑問題,演算法最終得到一個最短路徑樹。該演算法常用於路由演算法或者作為其他圖演算法的一個子模組。 演算法的思路 Dijkstra演算法採用的是一種貪心的策略,宣告一個數

    C# 網路程式設計簡單瀏覽器實現

          最近學習C#網路程式設計的HTTP協議程式設計,HTTP即Hypertext Transfer Protocol的縮寫,意為:超文字傳輸協議。其中與HTTP相關的知識主要有六個類的知識,分

    時間實現定時

    時間堆:將所有定時器中超時最小的一個作為心搏間隔,這樣,一旦心搏函式tick被呼叫,超時時間最小的一個定時器必然到期,我們就可以在tick函式裡處理該定時器,這樣就實現了較為精確的定時. 最小堆很適合這種方案,最小堆的堆頂永遠為最小的元素,這樣每次只要將堆頂的定時器處理,

    找出一的前K個數

    string nlog 浪費 art args 技術分享 str rate .net 描寫敘述: 給定一個整數數組。讓你從該數組中找出最小的K個數 思路: 最簡潔粗暴的方法就是將該數組進行排序,然後取最前面的K個數就可以。可是,本題要求的僅僅是求出最小的k個數就可以,用

    一、實現一個特殊的棧,在實現棧的基本功能的基礎上,再實現返回棧元素的操作

    empty util run print pri ont com res 字符串 請指教交流! 1 package com.it.hxs.c01; 2 3 import java.util.Stack; 4 5 /* 6 實現一個特殊的棧,在實現棧的基本

    c++用priority_queue實現,並求解大的n個數

    輸出 return bool rand cto and gre main 最小堆 1 //c++用priority_queue實現最小堆,並求解很多數中的最大的n個數 2 #include <iostream> 3 #include <queue&

    Android音視頻通話過程化成懸浮框的實現(類似Android8.0畫中畫效果)

    apk 添加 touch null cas 如果 動態添加 int sta 關於音視頻通話過程中最小化成懸浮框這個功能的實現,網絡上類似的文章很多,但是好像還沒看到解釋的較為清晰的,這裏因為項目需要實現了這樣的一個功能,今天我把它記錄下來,一方面為了以後用到便於自己查閱,一

    排序 大堆 Java實現

    堆排序 最大堆 最小堆 Java 堆排序啊,其實是一種數據結構,二叉樹,二叉樹分為是滿二叉樹和完全二叉樹。一棵深度為 k,且有 2k - 1 個節點稱之為滿二叉樹,完全二叉樹:深度為 k,有 n 個節點的二叉樹,當且僅當其每一個節點都與深度為 k 的滿二叉樹中序號為 1 至 n 的節點對應時,

    利用找出10億個數大的10000個數

    AS 如果 算法 最小值 分治 但是 空間 找出最大值 根節點 最小堆 最小堆是一種完全二叉樹,特點是根節點比兩個子節點都小(或者根節點比子節點都大) 過程 先找10000個數構建最小堆 依次遍歷10億個數,如果比最小堆的最小值大,則替換這個最小值,並重新構建最小堆 最後

    大堆、定義及其C++程式碼實現

    資料:https://blog.csdn.net/guoweimelon/article/details/50904346 但是它的最大堆刪除部分的程式碼有問題,詳見連結裡的評論區 定義 堆首先必須是一棵完全二叉樹 最大堆:完全二叉樹,父節點的值不小於子節點的值 最小堆:完全二叉樹,父節

    初學Java:計算陣列大值 ---計算陣列值----計算陣列之和----實現兩個陣列----拼接陣列擷取

    public class ArrayUtils{ //建立類(陣列工具類) //1.計算陣列中最大值 public static int arrayMaxElement(int [] data){ //建立方法 if(data == null){