Epoll的使用例子

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

 

posted @ 2019-11-26 10:31  小荷才楼尖尖角  Views(475)  Comments(0Edit  收藏  举报