当前位置:网站首页>[Muduo] poller abstract class

[Muduo] poller abstract class

2022-07-23 13:43:00 Cx330( ͡ _ ͡ °)

TcpServer We have an important component on , Namely The event loop (EventLoop), A thread corresponds to an event loop , One EventLoop There is a corresponding poller And a pile of channel,channel The last article is finished , The most important thing is here poller 了 .

Poller Why is it implemented as an abstract class ? because EventLoop It is impossible to call directly Epoll perhaps Poll, It uses this abstract class directly from the abstract level poller, At that time, reference different derived class objects to call its override method with the same name . It is very convenient to expand different IO Reuse capability . Namely Multiplexer .

Poller.h

#pragma once
#include "Timestamp.h"
#include "noncopyable.h"
#include <vector>
#include <unordered_map>

// As long as it is just a pointer declaration , Just make a pre declaration 
class Channel;
class EventLoop;

//muduo The core of the multi-channel event distributor in the library IO Reuse module 
class Poller: noncopyable
{
    public:
        using ChannelList = std::vector<Channel*>;

        Poller(EventLoop *loop);

        virtual ~Poller() = default;

        // Yes epoll It's equivalent to epoll_wait
        // Currently active Channel, Or interested in some events channel, need poller To take care of channel
        // To all IO Reuse and retain a unified interface , Let derived classes override 
        virtual Timestamp poll(int timeoutMs, ChannelList *activeChannels) = 0;
        
        // Yes epoll It's equivalent to epoll_ctl
        virtual void updateChannel(Channel *channel) = 0;
        // Yes epoll It's equivalent to epoll_del
        virtual void removeChannel(Channel *channel) = 0;

        // Judgment parameters channel Whether in the current poller among 
        bool hasChannel(Channel *channel) const;

        // Get one of the event loops poller, It's like in our singleton mode get instance equally , Get an instance 
        //EventLoop You can get the default through this interface IO Specific implementation of reuse 
        static Poller* newDefaultPoller(EventLoop *loop);

    private:
        EventLoop *ownerLoop_; // Definition poller Event loop to which it belongs EventLoop
    protected:
        //map Of ky:sockfd  value:sockfd Of channel Channel type 
        using ChannelMap =  std::unordered_map<int, Channel*>;
        ChannelMap channels_;

};




Poller.cc

#include "Channel.h"
#include "EventLoop.h"
#include "Logger.h"

#include <sys/epoll.h>

const int Channel::kNoneEvent = 0; 
const int Channel::kReadEvent = EPOLLIN | EPOLLPRI;
const int Channel::kWriteEvent = EPOLLOUT;


Channel::Channel(EventLoop *loop, int fd)
    :loop_(loop),fd_(fd),events_(0),revents_(0),index_(-1),tied_(false)
{}


Channel::~Channel(){}

//channel Inside tie When was the method called ?  Look back 
void Channel::tie(const std::shared_ptr<void> &obj)
{
    tie_ = obj; // Bind to weak smart pointer and observe strong smart pointer 
    tied_ = true;// After binding, it will be set to true
}

/**
 * @brief  When change channel Indicated by fd Of events After the event ,update Responsible for poller Inside change fd The corresponding time epoll_ctl
 * 
 * poller Where to? ? poller  Follow channel It's two different modules . because epoll Do not belong to channel tube , But they are both data EventLoop Of 
 * 
 * EventLoop  Contains ChannelList" That's one channel list ",  And a poller
 * 
 *  therefore channel I want to Channel register fd Corresponding events cannot be done , Because it doesn't poller object , So you have to go through EventLoop To do this 
 * 
 */
void Channel::update()
{
    // adopt Channel Of EventLoop, call poller The corresponding method of , register fd Of Events event 
    //add code
    //loop_->updateChannel(this);
}

// stay channel Of EventLoop In the container , Delete yourself 
void Channel::remove()
{
    //add code
    // loop_->removeChannel(this);
}


//fd obtain poller After notification , The 
void Channel::handleEvent(Timestamp receiveTime)
{
    if(tied_)
    {
        std::shared_ptr<void> guard = tie_.lock();
        if(guard)
        {
            handleEventWithhGuard(receiveTime);
        }
    }
    else
    {
        handleEventWithhGuard(receiveTime);
    }
}

// according to poller Notified channel Specific events that occurred , from channel Be responsible for calling specific callback operations 
void Channel::handleEventWithhGuard(Timestamp receiveTime)
{
    LOG_INFO("channel handleEvent revent:%d\n", revents_);

    if((revents_ & EPOLLHUP) && !(revents_ & EPOLLIN))
    {
        if(closeCallback_)
        {
            closeCallback_();
        }
    }
    // An error occurred in the event 
    if(revents_ & EPOLLERR)
    {
        if(errorCallback_)
        {
            errorCallback_();
        }
    }
    // Can read the event 
    if(revents_ & (EPOLLIN | EPOLLPRI))
    {
        if(readCallback_)
        {
            readCallback_(receiveTime);
        }
    }

    if(revents_ & EPOLLOUT)
    {
        if(writeCallback_)
        {
            writeCallback_();
        }
    }

}

Poller Static methods in a class :

static Poller* newDefaultPoller(EventLoop *loop);

Why not implement it directly in Poller.cc In file ?

1. If you really implement it in Poller.cc in , Grammatically speaking, there is no problem , Why? , Because your static side is defined in this class , Of course, it should be here cc File to define the implementation . But you have to pay attention to : This is to generate a specific one IO Reuse objects , And return a pointer to the base class , So do you have to include the header file of the derived class here . You can create one here poller Instantiate the object , Is this reasonable ?

Poller* newDefaultPoller(EventLoop *loop)
{
    return new EPollPoller();
}

Definitely unreasonable , Because in the inheritance structure poller It belongs to the upper base class , Derived classes can only reference base class header files , The base class cannot reference the header of the derived class , So you are in this abstract base class poller Directly reference the header file of the derived class , This is a bad implementation .

I'm a base class , Your derived class contains me naturally , As an abstract , Can I go include Of each of your derived classes ? Not reality

::getenv("key")  Get variables in the environment , similar json, The header file #include <stdlib.h>

  We need to create a new cc file :DefaultPoller.cc

#include "Poller.h"


#include <stdlib.h>

Poller* Poller::newDefaultPoller(EventLoop *loop)
{
    if(::getenv("MUDUO_USE_POLL"))
    {
        return nullptr; // Generate poll Example 
    }
    else
    {
        return nullptr; // Generate epoll Example 
    }
}

原网站

版权声明
本文为[Cx330( ͡ _ ͡ °)]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/204/202207230625160667.html