本篇文章在上一篇的基础上,使用 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;
}