仿muduo库实现高并发服务器--定时器模块的整合

目录

一、前置知识

二、TimeTask

1、成员变量

2、成员函数

三、时间轮TimerWheel

1、成员变量

2、成员函数

四、EventLoop中整合TimerWheel

[五、Channel Poll EventLoop timerwheel整体代码](#五、Channel Poll EventLoop timerwheel整体代码)


一、前置知识

timefd: 实现内核每隔一段时间,给进程一次超时时间(timefd可读)

timewheel: 实现每次执行Runtimetask,都可以执行一波到期任务的定时任务

要实现一个完整的秒级定时器,就需要将这两个功能整合到一起

timerfd设置为每秒钟触发一次定时任务,当事件被触发则运行一次timerwheel的runtimertask,执行以下所有定时任务

timerfd的事件监控与触发,可以融合EventLoop

下面的代码如果看不懂可以看我前面的前置知识详细的讲解的时间轮的思想

二、TimeTask

1、成员变量

定时任务id

定时任务的超时时间

定时任务要执行的任务

删除Timerwheel中保存的定时器对象

是否取消定时任务

2、成员函数

构造

cpp 复制代码
TimerTask(uint64_t id, uint32_t delay, const TaskFunc cd)
        : _id(id), _timeout(delay), _task_cd(cd), _canceled(false)
    {
    }

析构

cpp 复制代码
 ~TimerTask()
    {
        if (_canceled == false)
        {
            _task_cd();
        }

        _release();
    }

设置Release

cpp 复制代码
void SetRelease(const ReleaseFunc &cd)
    {
        _release = cd;
    }

取消定时任务

cpp 复制代码
 void Cancel()
    {
        _canceled = true;
    }

三、时间轮TimerWheel

1、成员变量

秒针(走到哪里哪里就被释放)

表盘最大容量(最大延迟时间)

表盘(vector)

查找表盘的任务(std::unordered_map<uint64_t, WeakTask> _timers;)

管理线程安全(EventLoop *_loop)

设置回调事件(std::unique_ptr<Channel> _timer_channel)

cpp 复制代码
 using WeakTask = std::weak_ptr<TimerTask>;
    using PtrTask = std::shared_ptr<TimerTask>;
    int _tick;     // 秒钟
    int _capacity; // 表盘最大数量
    std::vector<std::vector<PtrTask>> _wheel;
    std::unordered_map<uint64_t, WeakTask> _timers;
    int _timerfd; // 定时器描述符,可读事件回调就是读取计数器,执行任务
    EventLoop *_loop;
    std::unique_ptr<Channel> _timer_channel;

2、成员函数

构造

创建time_fd

_timer_fd的可读事件回调

cpp 复制代码
  void OnTime()
    {

       int times =  ReadTimefd();
       for(int i = 0; i<times; i++)
       {
         RunTimerTask();
       }
       
    }

读取_time_fd

cpp 复制代码
int ReadTimefd()
    {
        uint64_t times;
        int ret = read(_timerfd, &times, sizeof(times));
        if (ret < 0)
        {
            ERR_LOG("READ FAILED");
            abort();
        }
        return ret;
    }

执行表盘中的任务

cpp 复制代码
void RunTimerTask()
    {
        _tick = (_tick + 1) % _capacity;
        _wheel[_tick].clear();
    }

判断任务是否存在

因为定时器任务都涉及到对链接的操作,需要考虑线程安全,所以需要将对_timer_fd的操作压入到EventLoop任务队列中

涉及到对象前后的问题所以在内外进行实现,在那种只写声明

添加任务

cpp 复制代码
 void TimerAddLoop(uint64_t id, uint32_t delay, const TaskFunc &cd)
    {
        PtrTask ptr(new TimerTask(id, delay, cd));
        ptr->SetRelease(std::bind(&TimerWheel::RemoveTimer, this, id));
        _timers[id] = ptr;
        int pos = (_tick + delay) % _capacity;
        _wheel[pos].push_back(ptr);
    }

刷新任务

cpp 复制代码
 void TimerRefreshLoop(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it == _timers.end())
        {
            return;
        }
        PtrTask ptr = it->second.lock();
        int delay = ptr->DelayTime();
        int pos = (delay + _tick) % _capacity;
        _wheel[pos].push_back(ptr);
    }

取消定时任务

cpp 复制代码
  void CancelTaskLoop(uint32_t id)
    {
        auto it = _timers.find(id);
        if (it == _timers.end())
        {
            return;
        }
        PtrTask tr = it->second.lock();
        if (tr)
            tr->Cancel();
    }

四、EventLoop中整合TimerWheel

在成员变量中添加定时器模块

成员函数中添加删除延迟任务

cpp 复制代码
  void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &cd)
    {
        _time_wheel.TimerAdd(id, delay, cd);
    }
    void TimerRefresh(uint64_t id)
    {
        _time_wheel.TimerRefresh(id);
    }
    void TimerCancel(uint64_t id)
    {
        _time_wheel.TimerCancel(id);
    }
    bool HasTimer(uint64_t id)
    {
        return _time_wheel.HasTimer(id);
    }

五、Channel Poll EventLoop timerwheel整体代码

cpp 复制代码
class Poller;
class EventLoop;
class Channel
{
private:
    uint32_t _events;
    uint32_t _revents;
    int _fd;
    EventLoop *_loop;
    using EventCallBack = std::function<void()>;
    EventCallBack _read_callback;
    EventCallBack _write_callback;
    EventCallBack _error_callback;
    EventCallBack _close_callback;
    EventCallBack _event_callback;

public:
    Channel(EventLoop *loop, int fd) : _fd(fd), _loop(loop), _events(0), _revents(0)
    {
    }
    uint32_t Event()
    {
        return _events;
    }
    int Fd()
    {
        return _fd;
    }
    void SetEvent(uint32_t events)
    {
        _revents = events;
    }
    void SetReadCallback(const EventCallBack &cd)
    {
        _read_callback = cd;
    }
    void SetWriteCallback(const EventCallBack &cd)
    {
        _write_callback = cd;
    }
    void SetErrorCallback(const EventCallBack &cd)
    {
        _error_callback = cd;
    }
    void SetCloseCallback(const EventCallBack &cd)
    {
        _close_callback = cd;
    }
    void SetEventCallback(const EventCallBack &cd)
    {
        _event_callback = cd;
    }
    bool ReadAble() // 是否监控了可读
    {
        return _events & EPOLLIN;
    }
    bool WriteAble()
    {
        return _events & EPOLLOUT;
    }
    void EnableRead() // 启动读事件监控
    {
        _events |= EPOLLIN;
        Update();
    }
    void EnableWrite()
    {
        _events |= EPOLLOUT;
        Update();
    }
    void DisableRead()
    {
        _events &= ~EPOLLIN;
        Update();
    }
    void DisableWrite()
    {
        _events &= ~EPOLLOUT;
        Update();
    }
    void DisableAll()
    {
        _events = 0;
        Update();
    }
    void Remove();
    void Update();
    // 事件处理 一旦链接接触了事件,就调用了这个函数,自己触发什么自己决定
    void HandleEvents()
    {
        if (_revents & EPOLLIN || _revents & EPOLLRDBAND || _revents & EPOLLPRI)
        {
           
            if (_read_callback)
                _read_callback();
        }
        if (_revents & EPOLLOUT)
        {
            if (_event_callback)
                _event_callback();
            if (_write_callback)
                _write_callback();
        }
        else if (_revents & EPOLLERR)
        {
            if (_error_callback)
                _error_callback();
        }
        else if (_revents & EPOLLHUP)
        {
            if (_close_callback)
                _close_callback();
        }
         if (_event_callback)
                _event_callback();
    }
};
#define MAX_EPOLLEVENTS 1024
class Poller
{
private:
    int _epfd;
    std::unordered_map<int, Channel *> _channels;
    struct epoll_event _evs[MAX_EPOLLEVENTS];
    void Update(Channel *channel, int op)
    {
        int fd = channel->Fd();
        struct epoll_event ev;
         memset(&ev, 0, sizeof(ev)); 
        ev.data.fd = fd;
        ev.events = channel->Event(); 
        int ret = epoll_ctl(_epfd, op, fd, &ev);
       
        if (ret < 0)
        {
             ERR_LOG("EPOLLCTL FAILED! errno: %d, %s", errno, strerror(errno));
            abort();
        }
        return;
    }

public:
    Poller()
    {
        _epfd = epoll_create(MAX_EPOLLEVENTS);
        if (_epfd < 0)
        {
            ERR_LOG("EPOLL_CREATE FAILED");
            abort();
        }
    }
    bool HasChannel(Channel *channel)
    {
        auto it = _channels.find(channel->Fd());
        if (it == _channels.end())
        {
            return false;
        }
        return true;
    }
    // 修改添加事件监控
    void UpdateEvent(Channel *channel)
    {
        if (HasChannel(channel) == false)
        {
            Update(channel, EPOLL_CTL_ADD);
            _channels.insert(std::make_pair(channel->Fd(), channel));
            return;
        }
        return Update(channel, EPOLL_CTL_MOD);
    }
    void RemoveEvent(Channel *channel)
    {
        auto it = _channels.find(channel->Fd());
        if (it != _channels.end())
        {
            _channels.erase(it);
        }
        Update(channel, EPOLL_CTL_DEL);
    }
    void Poll(std::vector<Channel *> *active)
    {
        int nfds = epoll_wait(_epfd, _evs, MAX_EPOLLEVENTS, -1);
        if (nfds < 0)
        {
            if (errno == EINTR)
            {
                return;
            }
            ERR_LOG("EPOLL_WAIT FAILED");
            abort();
        }
        for (int i = 0; i < nfds; i++)
        {
            auto it = _channels.find(_evs[i].data.fd);
            assert(it != _channels.end());
            it->second->SetEvent(_evs[i].events);
            active->push_back(it->second);
        }
    }
};
using TaskFunc = std::function<void()>;
using ReleaseFunc = std::function<void()>;
class TimerTask
{
private:
    uint64_t _id;
    uint32_t _timeout;
    TaskFunc _task_cd;
    bool _canceled;
    ReleaseFunc _release;

public:
    TimerTask(uint64_t id, uint32_t delay, const TaskFunc cd)
        : _id(id), _timeout(delay), _task_cd(cd), _canceled(false)
    {
    }
    void SetRelease(const ReleaseFunc &cd)
    {
        _release = cd;
    }
    uint32_t DelayTime()
    {
        return _timeout;
    }
    ~TimerTask()
    {
        if (_canceled == false)
        {
            _task_cd();
        }

        _release();
    }
    void Cancel()
    {
        _canceled = true;
    }
};
class TimerWheel
{
private:
    using WeakTask = std::weak_ptr<TimerTask>;
    using PtrTask = std::shared_ptr<TimerTask>;
    int _tick;     // 秒钟
    int _capacity; // 表盘最大数量
    std::vector<std::vector<PtrTask>> _wheel;
    std::unordered_map<uint64_t, WeakTask> _timers;
    int _timerfd; // 定时器描述符,可读事件回调就是读取计数器,执行任务
    EventLoop *_loop;
    std::unique_ptr<Channel> _timer_channel;
    void RemoveTimer(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it != _timers.end())
        {
            _timers.erase(it);
        }
    }
    static int CreatTimerfd()
    {
        int timerfd = timerfd_create(CLOCK_MONOTONIC, 0);
        if (timerfd < 0)
        {
            ERR_LOG("TIMERFD_CREATE FALIED");
            abort();
        }
        struct itimerspec itm;
        itm.it_value.tv_sec = 1; // 设置第⼀次超时的时间
        itm.it_value.tv_nsec = 0;
        itm.it_interval.tv_sec = 1; // 第⼀次超时后,每隔多⻓时间超时
        itm.it_interval.tv_nsec = 0;
        timerfd_settime(timerfd, 0, &itm, NULL); // 启动定时器
        return timerfd;
    }
    int ReadTimefd()
    {
        uint64_t times;
        int ret = read(_timerfd, &times, sizeof(times));
        if (ret < 0)
        {
            ERR_LOG("READ FAILED");
            abort();
        }
        return ret;
    }
    void RunTimerTask()
    {
        _tick = (_tick + 1) % _capacity;
        _wheel[_tick].clear();
    }
    void OnTime()
    {

       int times =  ReadTimefd();
       for(int i = 0; i<times; i++)
       {
         RunTimerTask();
       }
       
    }
    void TimerAddLoop(uint64_t id, uint32_t delay, const TaskFunc &cd)
    {
        PtrTask ptr(new TimerTask(id, delay, cd));
        ptr->SetRelease(std::bind(&TimerWheel::RemoveTimer, this, id));
        _timers[id] = ptr;
        int pos = (_tick + delay) % _capacity;
        _wheel[pos].push_back(ptr);
    }
    // 刷新延迟任务
    void TimerRefreshLoop(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it == _timers.end())
        {
            return;
        }
        PtrTask ptr = it->second.lock();
        int delay = ptr->DelayTime();
        int pos = (delay + _tick) % _capacity;
        _wheel[pos].push_back(ptr);
    }

    void CancelTaskLoop(uint32_t id)
    {
        auto it = _timers.find(id);
        if (it == _timers.end())
        {
            return;
        }
        PtrTask tr = it->second.lock();
        if (tr)
            tr->Cancel();
    }

public:
    TimerWheel(EventLoop *loop) : _loop(loop), _tick(0), _capacity(60), _wheel(_capacity), _timerfd(CreatTimerfd()), _timer_channel(new Channel(_loop, _timerfd))
    {
        _timer_channel->SetReadCallback(std::bind(&TimerWheel::OnTime, this));
        _timer_channel->EnableRead();
    }
    void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &cd);
    void TimerRefresh(uint64_t id);
    void TimerCancel(uint64_t id);
    bool HasTimer(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it == _timers.end())
        {
            return false;
        }
        return true;
    }
};
class EventLoop
{
private:
    using Functor = std::function<void()>;
    std::thread::id _thread_id;
    int _event_fd;
    Poller _poller;
    std::unique_ptr<Channel> _event_channel;
    std::vector<Functor> _task;
    std::mutex _mutex;
    TimerWheel _time_wheel;
    void RunAllTask()
    {
        std::vector<Functor> functor;
        {
            std::unique_lock<std::mutex> _lock(_mutex);
            _task.swap(functor);
        }
        for (auto &f : functor)
        {
            f();
        }
        return;
    }
    static int CreatEventFd()
    {
        int efd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
        if (efd < 0)
        {
            ERR_LOG("EVENTFD FAILED");
            abort();
        }
        return efd;
    }
    void ReadEventFd()
    {
        uint64_t res = 0;
        int ret = read(_event_fd, &res, sizeof(res));
        if (ret < 0)
        {
            if (errno == EINTR ||errno == EAGAIN)
            {
                return;
            }
            ERR_LOG("READ FAILED");
            abort();
        }
        return;
    }
    void WeakUpEventFd()
    {
        uint64_t val = 1;
        int ret = write(_event_fd, &val, sizeof(val));
        if (ret < 0)
        {
            if (errno == EINTR ||errno == EAGAIN)
            {
                return;
            }
            ERR_LOG("WRITE FAILED");
            abort();
        }
        return;
    }

public:
    EventLoop()
        : _thread_id(std::this_thread::get_id()), _event_fd(CreatEventFd()), _event_channel(new Channel(this, _event_fd)), _time_wheel(this)
    {
        _event_channel->SetReadCallback(std::bind(&EventLoop::ReadEventFd, this));
        _event_channel->EnableRead();
    }
    void Start()
    {
        while (1)
        {
            std::vector<Channel *> active;
            _poller.Poll(&active);
            for (auto &channel : active)
            {
                channel->HandleEvents();
            }
            RunAllTask();
        }
    }

    bool IsInloop()
    {
        return (_thread_id == std::this_thread::get_id());
    }
    void AssertInloop()
    {
        assert(_thread_id == std::this_thread::get_id());
    }
    void RunInLoop(const Functor &cd)
    {
        if (IsInloop() == true)
        {
            return cd();
        }
        return QueueInLoop(cd);
    }
    void QueueInLoop(const Functor &cd)
    {
        {
            std::unique_lock<std::mutex> _lock(_mutex);
            _task.push_back(cd);
        }
        WeakUpEventFd();
    }
    void UpdateEvent(Channel *channel)
    {
        return _poller.UpdateEvent(channel);
    }
    void RemoveEvent(Channel *channel)
    {
        return _poller.RemoveEvent(channel);
    }
    void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &cd)
    {
        _time_wheel.TimerAdd(id, delay, cd);
    }
    void TimerRefresh(uint64_t id)
    {
        _time_wheel.TimerRefresh(id);
    }
    void TimerCancel(uint64_t id)
    {
        _time_wheel.TimerCancel(id);
    }
    bool HasTimer(uint64_t id)
    {
        return _time_wheel.HasTimer(id);
    }
void Channel::Update()
{
    _loop->UpdateEvent(this);
}
void Channel::Remove()
{
    _loop->RemoveEvent(this);
}
void TimerWheel::TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &cd)
{
    _loop->RunInLoop(std::bind(&TimerWheel::TimerAddLoop, this, id, delay, cd));
}
void TimerWheel::TimerRefresh(uint64_t id)
{
    _loop->RunInLoop(std::bind(&TimerWheel::TimerRefreshLoop, this, id));
}
void TimerWheel::TimerCancel(uint64_t id)
{
    _loop->RunInLoop(std::bind(&TimerWheel::CancelTaskLoop, this, id));
}
相关推荐
且从容.3 小时前
Ubuntu安装flume
linux·ubuntu·flume
承渊政道3 小时前
Linux网络学习【Reactor反应堆模式】
linux·网络·学习·ubuntu·reactor
讯捷蓝达5 小时前
戴尔R720xd服务器卡死在 “Configuring Memory...Done“,换了内存还是卡?问题根本不在内存
运维·服务器
且从容.6 小时前
ubuntu安装flink
linux·ubuntu·flink
数字新视界7 小时前
动环监控信创适配在智能机房管理中的应用价值与未来展望
大数据·服务器·数据库·动环监控系统·动力与环境监控系统
爱和冰阔落7 小时前
【Linux网络】TCP 服务器如何并发处理多个客户端?从 fork、僵尸进程到双重 fork
linux·运维·服务器·网络
程序员沉梦听雨7 小时前
WSL2的安装与使用
linux·wsl
微小的鱼8 小时前
Linux的渲染与显示系统链路
android·java·linux
lisanmengmeng8 小时前
alertmanger 标签 rules 打上分组标签
linux·运维·服务器
Android系统攻城狮9 小时前
Linux FFmpeg深度解析之av_write_frame调用流程与实战(三十三)
linux·运维·服务器·ffmpeg·音视频进阶·ffmpeg音视频