Muduo网络库源码复盘-核心类Eventloop

EventLoop功能:完成事件分发,处理,Muduo中的eventloop是单线程的,不会涉及到其他线程,所以无需锁操作即可完成IO,这也是Muduo网络库的核心思想(既一个EventLoop永远只在一个线程运行自己的Loop循环,从而避免复杂的多线程同步问题)

对外提供的接口:

 

    ///核心,EventLoop的所有功能最终在loop中实现
    void loop();
    ///接口,使得eventloop可以接受事件调用,并且完成定时功能
    ///定时功能由TimerQueue提供,会在以后相关的文章中讲解
    TimerId runAt(TimeStamp stamp,FUNC cb);
   
    
    TimerId runAfter(double interVal,FUNC cb);

    TimerId runEvery(double interval,FUNC cb);
    ///取消接口

    void cancel(TimerId toBeCancel);
    
    ///同上方的runAt等接口,不过是直接实时调用的
    void queueInLoop(FUNC cb);

    void runInLoop(FUNC cb);
    
    ///为Channel注入新的功能后更新
    void updateChannel(Channel * channel);
    
    ///完成多线程EventLoop调用接口的核心
    bool isInLoopThread() const;
    
    ///断言,上方的辅助
    void assertInLoopThread() ;
    
    ///设置Poller,poller的作用是IO多路复用
    void setPoller(Poller *poller);
    
    ///删除事件处理器
    void removeChannel(Channel *channel);
    
    bool isInLoopThread();
    
    ///调用排队的Func
    void doPendingFunc();

    void quit();

Loop核心:

void CzyNetFrame::EventLoop::loop()
{
    /// 在第一次调用loop前必须非运行状态
    assert(!m_isRunning);
    assertInLoopThread();
    m_isRunning = true;
    
    while (m_isRunning)
    {
        m_channelList.clear();
        TimeStamp now = m_uPtrPoller->poll(500, m_channelList);
        m_isHandleing = true;
        for (auto &channel : m_channelList)
        {
            m_currentActive = channel;
            channel->handleEvent(now);
        }
        m_isHandleing = false;
        doPendingFunc();
    }
}

loop就是在不停的调用poller提供的IO复用机制,填满自己的ChannelList,然后调用其channel提供的hanleEvent方法,达到IO多路复用,在IO后会调用所有悬挂的回调函数

EventLoop数据成员

    ///唤醒该EventLoop的fd
    int m_wakeUpFd;
    ///唤醒该EventLoop的channel
    std::unique_ptr<Channel> m_wakeUpChannel;
    ///用于判断当前是否在创建线程
    pid_t m_theradId;
    ChannelList m_channelList;
    ///判断是否还在运行
    bool m_isRunning{false};
    ///实现IO多路复用的Poller类
    std::unique_ptr<Poller> m_uPtrPoller;
    ///当前活跃的Channel
    Channel *m_currentActive{NULL};
    bool m_isHandleing{false};
    ///暗示是否在处理函数
    bool m_callingPendingFunctors{false};
    ///互斥锁,保护pengdingFunc的插入操作    
    std::mutex m_mux;  
    std::vector<FUNC> m_vecPendingFunctor;
    ///实现定时功能的Time类
    std::unique_ptr<TimerQueue> m_timeQueue;

在调用pedingFunc的时候,设置正在处理pengdingFunc的标志,方便后续处理这么一种情况:在处理pengdingFunc时,这个时候插入了一个pengding的线程,后续的还没处理完,等到后续的处理完之后,将阻塞在poller->poll()上,这个时候,这个插入的pengdingFunc将永远无法被处理,解决方法如下

void CzyNetFrame::EventLoop::doPendingFunc()
{
    std::vector<FUNC> functors;
    ///在这里设置标志
    m_callingPendingFunctors = true;
    {
        std::unique_lock<std::mutex> lk(m_mux);
        functors.swap(m_vecPendingFunctor);
    }
    for(const auto &func:functors){
        func();
    }
    m_callingPendingFunctors = false;
}



void CzyNetFrame::EventLoop::queueInLoop(FUNC cb)
{  
   {
    std::unique_lock<std::mutex > lk(m_mux); 
    m_vecPendingFunctor.push_back(std::move(cb));
   }
    ///当不在Loop线程中,或者碰到上文提到的情况时wakeUp
   if(!isInLoopThread() || m_callingPendingFunctors){
     wakeUp();
   }
}

判断当前线程是否是创建线程的方法

bool EventLoop::isInLoopThread() {
    return m_theradId == NowThread::tid();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值