本篇文章在上一篇的基础上,使用 epoll 实现了一个事件监听和回调处理的模块。如何编写一个使用该模块的例子呢? 监测什么类型的fd,监测什么类型的事件,监测到事件以后需要做什么?后来可以看看如何将该模块与socket , 回调函数, 线程池联系起来。
#include<sys/epoll.h> // epoll_create, epoll_ctl, epoll_wait #include <mutex> // std::mutex #include <functional> // std::function #include <iostream> #include <memory> // std::unique_ptr #include <unistd.h> // close class Epoll{ public: class ActiveEvents { public: ActiveEvents( int num, const struct epoll_event* events): num_( num ), events_( events ) { } int num() const { return num_; } const struct epoll_event* events() const { return events_; } private: int num_; const struct epoll_event* events_; }; Epoll(); ~Epoll(); int AddMonitorReadableEvent( int fd ); int AddMonitorWritableEvent( int fd ); int DeleteMonitoringEvent( int fd ); int ModifyMonitorEvent( int fd , int status ); void StartPolling(); void HandleEvents( int num, const struct epoll_event* events ); void Stop(); using EpollAwakeCallBack = std::function< void(const ActiveEvents*) > ; void SetAwakeCallBack( EpollAwakeCallBack* cb ); // 设置事件处理回调函数 private : int Add_Event( int fd, int event ); // 封装 epoll_ctl, 使函数语义看起来更明确 int Delete_Event( int fd, int event ); int Modify_Event( int fd, int event ); int epollfd_; std::unique_ptr< EpollAwakeCallBack > awake_cb_ ; static const int fd_size_; // 最多能处理的fd个数 std::mutex awake_cb_mutex_; // 由于使用std::unique_ptr保存回调函数指针,设置回调函数时需要加锁 std::mutex mutex_; }; const int Epoll::fd_size_ = 100 ; Epoll::Epoll() { epollfd_ = epoll_create(fd_size_); std::cout << "epollfd = " << epollfd_ << std::endl; } Epoll::~Epoll() { std::cout << "deleting epoll" << std::endl; close(epollfd_); } void Epoll::StartPolling() { const int EPOLLEVENTS = 100; struct epoll_event events[EPOLLEVENTS]; while (1) { auto ret = epoll_wait(epollfd_, events, EPOLLEVENTS, -1); std::cout << "awakening " << ret << std::endl; HandleEvents(ret, events); } } void Epoll::HandleEvents(int num, const struct epoll_event* events) { ActiveEvents active_events(num, events); std::unique_lock<std::mutex> lock(awake_cb_mutex_); if (awake_cb_) { (*awake_cb_)(&active_events); } } void Epoll::SetAwakeCallBack(EpollAwakeCallBack* cb) { std::unique_lock<std::mutex> lock(awake_cb_mutex_); awake_cb_.reset(cb); } int Epoll::AddMonitorReadableEvent(int fd) { // TODO: Are epoll_wait and epoll_ctl thread-safe? std::unique_lock<std::mutex> lock(mutex_); return Add_Event(fd, EPOLLIN | EPOLLONESHOT); } int Epoll::AddMonitorWritableEvent(int fd) { std::unique_lock<std::mutex> lock(mutex_); return Add_Event(fd, EPOLLOUT | EPOLLONESHOT); } int Epoll::DeleteMonitoringEvent(int fd) { std::unique_lock<std::mutex> lock(mutex_); return Delete_Event(fd, EPOLLIN | EPOLLONESHOT); } int Epoll::ModifyMonitorEvent(int fd, int status) { std::unique_lock<std::mutex> lock(mutex_); return Modify_Event(fd, status); } int Epoll::Add_Event(int fd, int event) { struct epoll_event ev; ev.events = event; ev.data.fd = fd; int ret = epoll_ctl(epollfd_, EPOLL_CTL_ADD, fd, &ev); return ret; } int Epoll::Delete_Event(int fd, int event) { struct epoll_event ev; ev.events = event; ev.data.fd = fd; int ret = epoll_ctl(epollfd_, EPOLL_CTL_DEL, fd, &ev); return ret; } int Epoll::Modify_Event(int fd, int event) { struct epoll_event ev; ev.events = event; ev.data.fd = fd; int ret = epoll_ctl(epollfd_, EPOLL_CTL_MOD, fd, &ev); return ret; } int main(){ Epoll a; return 0; }