目录
[五、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, ×, 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, ×, 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));
}