zoukankan      html  css  js  c++  java
  • [高并发引擎]定时器模块

    在服务端开发,特别是游戏服务端开发过程中,定时器必不可少,而且用得非常多。看网上有的人是直接在线程的loop中每次都对定时器进行检测,例如:

     
    1. void loop() {  
    2.     while (running) {  
    3.         // Do same work  
    4.         Timer timer = getTopTimer();  
    5.         while (timer->time < now()) {  
    6.             timer->dg();  
    7.             timer = getTopTimer();  
    8.         }  
    9.         // Do same work  
    10.     }  
    11. }  

    这样做每次循环都会检测定时器,浪费CPU,而且定时器精确性不高。

    现在Linux下有了新的实现定时器的方案,使用timerfd,它将定时器抽象成文件描述符,可以结合epoll一起使用,非常方便,但Linux内核版本必须大于等于2.6.25。

    下面是我最近封装的定时器,性能不会随着定时器的增加而降低。

     
    1. class Timer : public boost::noncopyable, public boost::enable_shared_from_this<Timer> {   
    2. friend class TimerManager;   
    3. public:   
    4.     DEFINE_PTR(Timer);   
    5.     typedef boost::function<void (Timer::ptr)> EntryPoint;   
    6.   
    7. private:   
    8.     Timer(microsec_t next, microsec_t interval, EntryPoint entryPoint, const boost::weak_ptr<TimerManager> &timerMgr);   
    9.   
    10.     // Constructor for dummy object   
    11.     Timer(microsec_t next)   
    12.         : m_next(next)   
    13.         , m_interval(0)   
    14.     {}   
    15.   
    16. public:   
    17.     bool cancel();   
    18.   
    19.     bool refresh();   
    20.   
    21.     //bool reset(microsec_t interval, bool fromNow = false);   
    22.   
    23. private:   
    24.     microsec_t m_next;   
    25.     microsec_t m_interval; // 如果m_interval等于0,代表定时器只触发一次   
    26.     EntryPoint m_entryPoint;   
    27.     boost::weak_ptr<TimerManager> m_timerMgr;   
    28. };  
     
    1. class TimerManager : boost::noncopyable, public boost::enable_shared_from_this<TimerManager> {   
    2. friend class Timer;   
    3. public:   
    4.     DEFINE_PTR(TimerManager);   
    5.   
    6. public:   
    7.     TimerManager(IoScheduler &scheduler);   
    8.   
    9.     virtual ~TimerManager();   
    10.   
    11.     void stop();   
    12.   
    13.     Timer::ptr registerTimerAt(microsec_t next, microsec_t interval, Timer::EntryPoint entryPoint);   
    14.   
    15.     Timer::ptr registerTimerAfter(microsec_t next, microsec_t interval, Timer::EntryPoint entryPoint);   
    16.   
    17.     bool hasTimer();   
    18.   
    19.     static microsec_t now();   
    20.   
    21. protected:   
    22.     void run();   
    23.     void processTimers();   
    24.     void setTimer(const microsec_t &next);   
    25.   
    26. private:   
    27.     struct TimerLess {   
    28.         bool operator() (const Timer::ptr &lhs, const Timer::ptr &rhs) const;   
    29.     };   
    30.   
    31. private:   
    32.     typedef std::set<Timer::ptr, TimerLess> Timers;   
    33.     ThreadMutex m_mutex;   
    34.     IoScheduler &m_scheduler;   
    35.     int m_timerFd; // timerfd   
    36.     io_event_t m_registerEvent;   
    37.     Timers m_timers;   
    38.     bool m_running;   
    39. };  
     
    1. TimerManager::TimerManager(IoScheduler &scheduler)   
    2.     : m_scheduler(scheduler)   
    3.     , m_running(false)   
    4. {   
    5.     FUNCTION_TRACKER();   
    6.     m_timerFd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK);   
    7.     if (m_timerFd == -1) {   
    8.         G_THROW_EXCEPTION_FROM_LAST_ERROR_API("timerfd_create");   
    9.     }   
    10.     m_scheduler.registerEvent(m_timerFd, IoScheduler::READ);   
    11.     m_registerEvent = IoScheduler::READ;   
    12.     m_running = true;   
    13.     m_scheduler.schedule(boost::bind(&TimerManager::run, this), true);   
    14. }   
    15.   
    16. /*virtual*/ TimerManager::~TimerManager() {   
    17.     FUNCTION_TRACKER();   
    18.     close(m_timerFd);   
    19. }   
    20.   
    21. void TimerManager::stop() {   
    22.     FUNCTION_TRACKER();   
    23.     ThreadMutex::Guard guard(m_mutex);   
    24.     if (m_running) {   
    25.         m_running = false;   
    26.         G_ASSERT(m_registerEvent != IoScheduler::NONE);   
    27.         m_scheduler.cancelWait(m_timerFd, IoScheduler::READ);   
    28.   
    29.         m_scheduler.unregisterEvent(m_timerFd, (IoScheduler::Event)m_registerEvent);   
    30.         m_registerEvent = IoScheduler::NONE;   
    31.     }   
    32. }   
    33.   
    34. Timer::ptr TimerManager::registerTimerAt(microsec_t next, microsec_t interval,   
    35.     Timer::EntryPoint entryPoint)   
    36. {   
    37.     FUNCTION_TRACKER();   
    38.     Timer::ptr timer(new Timer(next, interval, entryPoint, shared_from_this()));   
    39.     ThreadMutex::Guard guard(m_mutex);   
    40.     Timers::iterator it = m_timers.insert(timer).first;   
    41.     bool firstTimer = (it == m_timers.begin());   
    42.     if (firstTimer) {   
    43.         setTimer(timer->m_next);   
    44.     }   
    45.     return timer;   
    46. }   
    47.   
    48. Timer::ptr TimerManager::registerTimerAfter(microsec_t next,   
    49.     microsec_t interval, Timer::EntryPoint entryPoint)   
    50. {   
    51.     FUNCTION_TRACKER();   
    52.     Timer::ptr timer(new Timer(now() + next, interval, entryPoint, shared_from_this()));   
    53.     ThreadMutex::Guard guard(m_mutex);   
    54.     Timers::iterator it = m_timers.insert(timer).first;   
    55.     bool firstTimer = (it == m_timers.begin());   
    56.     if (firstTimer) {   
    57.         setTimer(timer->m_next);   
    58.     }   
    59.     return timer;   
    60. }   
    61.   
    62. bool TimerManager::hasTimer() {   
    63.     FUNCTION_TRACKER();   
    64.     ThreadMutex::Guard guard(m_mutex);   
    65.     return !m_timers.empty();   
    66. }   
    67.   
    68. /*static*/ microsec_t TimerManager::now() {   
    69.     FUNCTION_TRACKER();   
    70.     return getCurrentMicroSecond();   
    71. }   
    72.   
    73. void TimerManager::run() {   
    74.     FUNCTION_TRACKER();   
    75.     G_LOG_INFO(g_logger) << "Timer manager fiber run";   
    76.     uint64_t data;   
    77.     while (m_running) {   
    78.         m_scheduler.asyncWait(m_timerFd, IoScheduler::READ);   
    79.         if (read(m_timerFd, &data, sizeof(data)) == -1) {   
    80.             if (errno != EAGAIN) {   
    81.                 G_THROW_EXCEPTION_FROM_LAST_ERROR_API("read");   
    82.             }   
    83.             continue;   
    84.         }   
    85.         G_ASSERT(data == 1);   
    86.         processTimers();   
    87.     }   
    88.     G_LOG_INFO(g_logger) << "Timer manager fiber exit";   
    89. }   
    90. void TimerManager::processTimers() {   
    91.     FUNCTION_TRACKER();   
    92.     ThreadMutex::Guard guard(m_mutex);   
    93.     microsec_t nowTime = now();   
    94.     Timers::iterator it = m_timers.begin();   
    95.     while (it != m_timers.end()) {   
    96.         Timer::ptr timer = *it;   
    97.         if (timer->m_next > nowTime) {   
    98.             setTimer(timer->m_next);   
    99.             return;   
    100.         }   
    101.         m_timers.erase(it);   
    102.         G_ASSERT(timer->m_entryPoint);   
    103.         if (timer->m_interval != 0) {   
    104.             timer->m_next = nowTime + timer->m_interval;   
    105.             m_timers.insert(timer);   
    106.         }   
    107.         m_scheduler.schedule(boost::bind(timer->m_entryPoint, timer), true);   
    108.         it = m_timers.begin();   
    109.     }   
    110.     return;   
    111. }   
    112.   
    113. void TimerManager::setTimer(const microsec_t &next) {   
    114.     FUNCTION_TRACKER();   
    115.     itimerspec val;   
    116.     val.it_value.tv_sec = next / MICROSECOND_PER_SECOND;   
    117.     val.it_value.tv_nsec = (next % MICROSECOND_PER_SECOND) * 1000;   
    118.     val.it_interval.tv_sec = 0;   
    119.     val.it_interval.tv_nsec = 0;   
    120.     if (timerfd_settime(m_timerFd, TFD_TIMER_ABSTIME, &val, NULL) == -1) {   
    121.         G_THROW_EXCEPTION_FROM_LAST_ERROR_API("timerfd_settime");   
    122.     }   
    123. }   
    124.   
    125. bool TimerManager::TimerLess::operator() (const Timer::ptr &lhs, const Timer::ptr &rhs) const {   
    126.     if (!lhs) {   
    127.         return true;   
    128.     } else if (!rhs) {   
    129.         return false;   
    130.     }   
    131.     if (lhs->m_next < rhs->m_next) {   
    132.         return true;   
    133.     } else if (lhs->m_next > rhs->m_next) {   
    134.         return false;   
    135.     } else {   
    136.         return lhs.get() < rhs.get(); // 保证TimerManager中能包含两个m_next一样的Timer   
    137.     }   
    138. }  
  • 相关阅读:
    第七周作业
    第六周作业
    第五周作业
    第四周作业
    第三周作业
    第二周作业
    第一周作业
    老鼠与盈利
    币值转换
    2015 USP-ICMC gym 100733 J. Summer Wars
  • 原文地址:https://www.cnblogs.com/libgod/p/3231787.html
Copyright © 2011-2022 走看看