http服务器_简易定时器的设计与C++实现(ref muduo)

http服务器_简易定时器的设计与C++实现(ref muduo)

一、定时器的意义

  在网络程序中经常需要处理定时事件,比如定时检测一个客户端连接的活动状态,或者设定时间关闭客户端连接等。服务器程序通常管理着大量的定时器,如何高效的组织和管理这些定时器,使得其能在预期的时间点被触发,而且不影响服务器的主要逻辑,对于服务器的性能有很大的影响。

二、定时器管理的结构设计

  传统的最简单的管理方式是采用按照时间排好序的线性表如排序链表,常用操作的复杂度为O(N)所以在管理大量的定时器时效率不高。
  第二种方案是采用二叉堆组织的优先队列,这样常见操作的复杂度就可以降为O(logN)。而且还可以利用STL现有的容器priority_queue。

二、定时器的实现

//timer.h

#ifndef __TIMER_H__
#define __TIMER_H__

#include <iostream>
#include <cassert>
#include <functional>
#include <mutex>
#include <vector>
#include <queue>
#include <chrono>

namespace huhu{

using TimeoutCallBack = std::function<void()>;//回调函数
using Clock = std::chrono::high_resolution_clock;//拥有最小计次周期的时钟
using MS = std::chrono::milliseconds;
//time_point表示从格林威治标准时间(1970-01-01 00:00:00.000)开始到指定时间的计次周期数
using Timestamp = Clock::time_point;
//forward declaration
class HttpRequest;

class Timer {
public:
    Timer(const Timestamp& when, const TimeoutCallBack& cb)
        :m_expire_time(when),
        m_timer_callback(cb),
        m_delete(false){}

    ~Timer(){}

    void del() {m_delete = true;}
    bool isDeleted() {return m_delete;}
    Timestamp getExpireTime() const {return m_expire_time;}
    void runCallBack() {m_timer_callback();}

private:
    Timestamp m_expire_time;
    TimeoutCallBack m_timer_callback;
    bool m_delete;

};// class Timer

struct cmp{
    //functor
    //仿函数,到期时间短的放前面
    bool operator()(Timer* a, Timer* b){
        assert(a != nullptr && b != nullptr);
        return (a->getExpireTime()) > (b->getExpireTime());
    }
};

class TimerManager{
public:
    TimerManager()
        :m_now(Clock::now()){}
    ~TimerManager(){}

    void updateTime() {m_now = Clock::now();}
    void addTimer(HttpRequest* request, const int& timeout, const TimeoutCallBack& cb);
    void delTimer(HttpRequest* request);
    void handleExpireTimer();//处理定时器事件
    int getNextExpireTime();//获取下一个定时器超时的时间

private:
    using TimerQueue = std::priority_queue<Timer*, std::vector<Timer*>, cmp>;//优先队列管理定时器
    TimerQueue m_timer_queue;
    Timestamp m_now;
    std::mutex m_lock;
};//class TimerManager

}// namespace huhu

#endif //__TIMER_H__
//timer.cpp
#include "../include/Timer.h"
#include "../include/HttpRequest.h"

#include <cassert>

using namespace huhu;
    
void TimerManager::addTimer(HttpRequest* request, \
                     const int& timeout, \
                     const TimeoutCallBack& cb){
                     
    std::unique_lock<std::mutex> lock(m_lock);
    assert(request != nullptr);

    updateTime();
    Timer* timer = new Timer(m_now + MS(timeout), cb);
    m_timer_queue.push(timer);

    // Call addTimer twice for the same request, you need to remove the previous timer
    if(request->getTimer() != nullptr)
        delTimer(request);

    request->setTimer(timer);
}

//handleExpireTimers->runCallBack->__closeConnection->delTimer
void TimerManager::delTimer(HttpRequest* request){
    assert(request != nullptr);

    Timer* timer = request->getTimer();
    if(timer == nullptr) return;
    //lazy delete
    timer->del();

    request->setTimer(nullptr);
}

void TimerManager::handleExpireTimer(){
    std::unique_lock<std::mutex> lock(m_lock);
    updateTime();
    while(!m_timer_queue.empty()) {
        Timer* timer = m_timer_queue.top();
        assert(timer != nullptr);
        //是否已删除检测
        if(timer->isDeleted()) {
            m_timer_queue.pop();
            if(timer != nullptr){
                delete timer;
            }
            continue;
        }

        // check pri_queue front,if not timeout, return
        if(std::chrono::duration_cast<MS>(timer->getExpireTime() - m_now).count() > 0) {
            return;
        }
        // timeout
        timer->runCallBack();
        m_timer_queue.pop();
        if(timer != nullptr){
            delete timer;
        }
    }
}

int TimerManager::getNextExpireTime(){
    std::unique_lock<std::mutex> lock(m_lock);
    updateTime();
    int res = -1;
    while(!m_timer_queue.empty()) {
        Timer* timer = m_timer_queue.top();
        if(timer->isDeleted()) {
            m_timer_queue.pop();
            if(timer != nullptr){
                delete timer;
            }
            continue;
        }
        res = std::chrono::duration_cast<MS>(timer->getExpireTime() - m_now).count();
        res = (res < 0) ? 0 : res;
        break;
    }
    return res;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值