zoukankan      html  css  js  c++  java
  • 优先队列实现定时器

    http://www.cnblogs.com/lewiskyo/p/6359789.html 上文介绍了使用数组实现定时器,但因为插入和删除定时器的效率太低,所以这里改用优先队列实现一次。

    实现代码如下:

      1 #include <iostream>
      2 #include <sys/time.h>
      3 #include <unistd.h>
      4 #include <thread>
      5 #include <vector>
      6 #include <map>
      7 #include <memory>
      8 #include <mutex>
      9 #include <stdlib.h>
     10 #include <algorithm>
     11 #include <queue>
     12 
     13 using namespace std;
     14 
     15 #define THREAD_COUNT 4
     16 
     17 typedef struct TimerInfo
     18 {
     19     int id;
     20     long expired;     //超时时间戳(ms)
     21     bool is_working;  //用于判断该定时器是否有效
     22     bool is_repeat;  // 是否为循环定时器标识
     23     long interval; //循环定时器循环间隔
     24 
     25 } TimerInfo;
     26 
     27 // 排序函数
     28 class comp
     29 {
     30 public:
     31     bool operator()(const shared_ptr<TimerInfo> &t1, const shared_ptr<TimerInfo> &t2)
     32     {
     33         if(t1.get()->expired > t2.get()->expired)
     34             return true;
     35         else
     36             return false;
     37     }
     38 };
     39 
     40 
     41 typedef struct TimerMng
     42 {
     43     int id;
     44     
     45     priority_queue<shared_ptr<TimerInfo>, vector<shared_ptr<TimerInfo> >, comp> timer_queue;   // 优先队列
     46     map<int, shared_ptr<TimerInfo> > timer_map;   //id到定时器的映射 用于根据id取消定时器
     47 
     48     mutex mtx;
     49 
     50     struct timeval now;
     51 
     52     TimerMng()
     53     {
     54         id = 0;
     55     }
     56 
     57 } TimerMng;
     58 
     59 TimerMng t_mng;
     60 
     61 void add_timer(bool is_repeat, long expired, long interval)
     62 {
     63     TimerInfo *t_info = new TimerInfo();
     64     t_info->is_repeat = is_repeat;
     65     t_info->expired = expired;
     66     t_info->interval = interval;
     67     t_info->is_working = true;
     68 
     69     shared_ptr<TimerInfo> timer_info(t_info);
     70 
     71     lock_guard<mutex> guard(t_mng.mtx);
     72     int now_id = t_mng.id++;
     73     t_info->id = now_id;
     74 
     75     t_mng.timer_queue.push(timer_info);
     76 
     77     t_mng.timer_map.insert(pair<int, shared_ptr<TimerInfo> >(now_id, timer_info) );
     78 
     79 }
     80 
     81 void update_time()
     82 {
     83     gettimeofday(&t_mng.now, NULL);
     84 }
     85 
     86 void execute_timer()
     87 {
     88     long now_usec = t_mng.now.tv_sec * 1000 + t_mng.now.tv_usec / 1000;
     89 
     90     while(true) 
     91     {
     92         lock_guard<mutex> guard(t_mng.mtx);
     93 
     94         if (t_mng.timer_queue.empty())
     95             break;
     96 
     97         shared_ptr<TimerInfo> first = t_mng.timer_queue.top();
     98 
     99         if (first.get()->expired > now_usec )
    100             break;
    101 
    102         if (first.get()->is_working)
    103         {
    104             // do something here
    105             cout << "timer execute succ, now: " << now_usec <<  " id: " << first.get()->id << " " << "expired: " << first.get()->expired << endl;
    106         }
    107 
    108         map<int, shared_ptr<TimerInfo> >::iterator map_iter = t_mng.timer_map.find( first.get()->id);
    109 
    110         // 从map中移除
    111         t_mng.timer_map.erase(map_iter);
    112 
    113         // 从队列中移除
    114         t_mng.timer_queue.pop();
    115 
    116     }
    117 }
    118 
    119 
    120 void timer_thread()
    121 {
    122     while(1)
    123     {
    124         update_time();
    125         execute_timer();
    126         // 1ms 1次循环
    127         usleep(1000);
    128     }
    129 }
    130 
    131 void worker_thread()
    132 {
    133     srand((unsigned)time(0));
    134     while(1)
    135     {
    136         struct timeval now;
    137         gettimeofday(&now, NULL);
    138 
    139         int rand_sec = rand() % 5 + 1;
    140         int rand_usec = rand() % 900000 + 1;
    141 
    142         long expired = (now.tv_sec + rand_sec) * 1000 + ( rand_usec / 1000 );
    143         add_timer(false, expired, 0);
    144 
    145         sleep(rand() % 2 + 1);    
    146     }
    147 }
    148 
    149 
    150 int main()
    151 {
    152     thread t1(timer_thread);
    153 
    154     vector<thread> v_thread;
    155 
    156     for (int i = 0; i < THREAD_COUNT; ++i)
    157     {
    158         v_thread.push_back(thread(worker_thread));
    159     }
    160 
    161     t1.join();
    162 
    163     for (int i = 0; i < THREAD_COUNT; ++i)
    164     {
    165         v_thread[i].join();
    166     }
    167 }

    代码与使用数组实现的大致相同,只是换了队列实现,而且在add_timer时直接使用优先队列的接口 push,

    在移除定时器时使用接口 pop即可.

    实现效率:

    add_timer 已序堆中添加数据 O(log(N)).

    execute_timer 最小已序堆中删除根节点,选取新的根节点 O(log(N)).

    可见比起数组实现的效率要高.

    优先队列(堆)的性质可以参考: http://blog.csdn.net/zhang20072844/article/details/10286997

    Coding Life
  • 相关阅读:
    python之enumerate
    Python中的集合set
    SGU 分类
    太空飞行计划 最大权闭合图
    1.飞行员配对 二分图匹配(输出方案)/最大流斩
    poj1149最大流经典构图神题
    hdu1569 方格取数 求最大点权独立集
    最大独立集 最小点覆盖 最小边覆盖 最小路径覆盖 最大团
    hdu3491最小割转最大流+拆点
    hdu3987,最小割时求最少割边数
  • 原文地址:https://www.cnblogs.com/lewiskyo/p/6359858.html
Copyright © 2011-2022 走看看