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();
}