本篇博客针对EventLoop类做下小结。
博客代码来自于陈硕的muduo网络库,github地址https://github.com/chenshuo/muduo
学习笔记:
muduo网络库的线程类遵循one loop per thread。顾名思义每个线程只能有一个EventLoop对象,因此EventLoop独享的构造函数会检查当前线程是否已经创建了其它EventLoop对象,如果已经创建则终止程序。创建了EventLoop的线程就是IO线程,其主要功能是运行时间循环EventLoop::loop(),在该循环中调用Poller::poll()执行阻塞式等待监听事件的响应,执行对应的回调函数。EventLoop对象可以在多线程使用,但是它的某些成员函数只有在EventLoop的创建者线程使用才是线程安全的(避免race-condition),EventLoop通过将调用函数传入pendingFunctors_,利用wakeupFd_唤醒EventLoop的创建者线程通知它及时执行pendingFunctors_中的函数。
EventLoop.h
#ifndef MUDUO_NET_EVENTLOOP_H
#define MUDUO_NET_EVENTLOOP_H
#include <atomic>
#include <functional>
#include <vector>
#include <boost/any.hpp>
#include "muduo/base/Mutex.h"
#include "muduo/base/CurrentThread.h"
#include "muduo/base/Timestamp.h"
#include "muduo/net/Callbacks.h"
#include "muduo/net/TimerId.h"
namespace muduo
{
namespace net
{
class Channel;
class Poller;
class TimerQueue;
///
/// Reactor, at most one per thread.
///
/// This is an interface class, so don't expose too much details.
class EventLoop : noncopyable
{
public:
typedef std::function<void()> Functor;
EventLoop();
~EventLoop(); // force out-line dtor, for std::unique_ptr members.
///
/// Loops forever.
///
/// Must be called in the same thread as creation of the object.
///
void loop();
/// Quits loop.
///
/// This is not 100% thread safe, if you call through a raw pointer,
/// better to call through shared_ptr<EventLoop> for 100% safety.
void quit();
///
/// Time when poll returns, usually means data arrival.
///
Timestamp pollReturnTime() const { return pollReturnTime_; }
int64_t iteration() const { return iteration_; }
/// Runs callback immediately in the loop thread.
/// It wakes up the loop, and run the cb.
/// If in the same loop thread, cb is run within the function.
/// Safe to call from other threads.
void runInLoop(Functor cb);
/// Queues callback in the loop thread.
/// Runs after finish pooling.
/// Safe to call from other threads.
void queueInLoop(Functor cb);
size_t queueSize() const;
// timers
// 以下3个run函数是对定时器的使用
///
/// Runs callback at 'time'.
/// Safe to call from other threads.
///
TimerId runAt(Timestamp time, TimerCallback cb);
///
/// Runs callback after @c delay seconds.
/// Safe to call from other threads.
///
TimerId runAfter(double delay, TimerCallback cb);
///
/// Runs callback every @c interval seconds.
/// Safe to call from other threads.
///
TimerId runEvery(double interval, TimerCallback cb);
///
/// Cancels the timer.
/// Safe to call from other threads.
///
void cancel(TimerId timerId);
// internal usage
/*一个EventLoop可能在多个线程使用,但是其内部某些资源使用不允许跨线程(避免rece-condition),
比如上面3个run函数可以在其它线程调用,但是run函数里面涉及对定时队列的读写,多线程读写必须加锁,
为了避免加锁,让涉及到数据读写的部分封装成函数,暂存到pendingFunctors_队列中,在往wakeupFd_
写入8个字节,唤醒EventLoop对象的所属线程,线程被唤醒后在loop()从pendingFunctors_队列中取出
之前暂存的函数继续执行,这样避免了多线程读写同一份资源。
*/
void wakeup();
void updateChannel(Channel* channel);
void removeChannel(Channel* channel);
bool hasChannel(Channel* channel);
// pid_t threadId() const { return threadId_; }
void assertInLoopThread()
{
if (!isInLoopThread())
{
abortNotInLoopThread();
}
}
//判断当前对EventLoop的调用是否在该EventLoop所属的线程中
bool isInLoopThread() const { return threadId_ == CurrentThread::tid(); }
// bool callingPendingFunctors() const { return callingPendingFunctors_; }
bool eventHandling() const { return eventHandling_; }
//context暂时没用上
void setContext(const boost::any& context)
{ context_ = context; }
const boost::any& getContext() const
{ return context_; }
boost::any* getMutableContext()
{ return &context_; }
//获取该线程的EventLoop指针
static EventLoop* getEventLoopOfCurrentThread();
private:
void abortNotInLoopThread();//调用者不在EventLoop的创建线程则异常退出
void handleRead(); //EventLoop所属的线程被唤醒
//其它线程对该EventLoop的函数调用暂存到队列中,待该EventLoop所属的线程被唤醒后执行
void doPendingFunctors();
void printActiveChannels() const; // DEBUG
typedef std::vector<Channel*> ChannelList;
bool looping_; /* atomic */
std::atomic<bool> quit_;//std::atomic类型无需加锁
bool eventHandling_; /* atomic */
bool callingPendingFunctors_; /* atomic */
int64_t iteration_;
const pid_t threadId_;//线程id,判断调用者是否在当前线程
Timestamp pollReturnTime_;
std::unique_ptr<Poller> poller_;//用于实现事件监控
std::unique_ptr<TimerQueue> timerQueue_;//时间队列
int wakeupFd_;//用于其他线程唤醒该线程
// unlike in TimerQueue, which is an internal class,
// we don't expose Channel to client.
std::unique_ptr<Channel> wakeupChannel_;//唤醒当前线程的Channel
boost::any context_;//没用过
// scratch variables
ChannelList activeChannels_;//保存从Poller::poll()返回的活跃Channel
Channel* currentActiveChannel_;
mutable MutexLock mutex_;
std::vector<Functor> pendingFunctors_ GUARDED_BY(mutex_);//暂存其它线程传入的函数
};
} // namespace net
} // namespace muduo
#endif // MUDUO_NET_EVENTLOOP_H
EventLoop.cpp
#include "muduo/net/EventLoop.h"
#include "muduo/base/Logging.h"
#include "muduo/base/Mutex.h"
#include "muduo/net/Channel.h"
#include "muduo/net/Poller.h"
#include "muduo/net/SocketsOps.h"
#include "muduo/net/TimerQueue.h"
#include <algorithm>
#include <signal.h>
#include <sys/eventfd.h>
#include <unistd.h>
using namespace muduo;
using namespace muduo::net;
namespace
{
__thread EventLoop* t_loopInThisThread = 0;
const int kPollTimeMs = 10000;
int createEventfd()
{
int evtfd = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
if (evtfd < 0)
{
LOG_SYSERR << "Failed in eventfd";
abort();
}
return evtfd;
}
#pragma GCC diagnostic ignored "-Wold-style-cast"
class IgnoreSigPipe
{
public:
IgnoreSigPipe()
{
::signal(SIGPIPE, SIG_IGN);
// LOG_TRACE << "Ignore SIGPIPE";
}
};
#pragma GCC diagnostic error "-Wold-style-cast"
IgnoreSigPipe initObj;
} // namespace
EventLoop* EventLoop::getEventLoopOfCurrentThread()
{
return t_loopInThisThread;
}
EventLoop::EventLoop()
: looping_(false),
quit_(false),
eventHandling_(false),
callingPendingFunctors_(false),
iteration_(0),
threadId_(CurrentThread::tid()),
poller_(Poller::newDefaultPoller(this)),
timerQueue_(new TimerQueue(this)),
wakeupFd_(createEventfd()),
wakeupChannel_(new Channel(this, wakeupFd_)),
currentActiveChannel_(NULL)
{
LOG_DEBUG << "EventLoop created " << this << " in thread " << threadId_;
if (t_loopInThisThread)
{
LOG_FATAL << "Another EventLoop " << t_loopInThisThread
<< " exists in this thread " << threadId_;
}
else
{
t_loopInThisThread = this;
}
//wakeupChannel_通过监听读事件,其它IO线程可以通过wakeup()唤醒当前线程
wakeupChannel_->setReadCallback(
std::bind(&EventLoop::handleRead, this));
// we are always reading the wakeupfd
wakeupChannel_->enableReading();
}
EventLoop::~EventLoop()
{
LOG_DEBUG << "EventLoop " << this << " of thread " << threadId_
<< " destructs in thread " << CurrentThread::tid();
wakeupChannel_->disableAll();
wakeupChannel_->remove();
::close(wakeupFd_);
t_loopInThisThread = NULL;
}
void EventLoop::loop()
{
assert(!looping_);
assertInLoopThread();
looping_ = true;
quit_ = false; // FIXME: what if someone calls quit() before loop() ?
LOG_TRACE << "EventLoop " << this << " start looping";
while (!quit_)
{
activeChannels_.clear();
//从poll()获取得到响应的Channel
pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_);
++iteration_;
if (Logger::logLevel() <= Logger::TRACE)
{
printActiveChannels();
}
// TODO sort channel by priority
eventHandling_ = true;
for (Channel* channel : activeChannels_)
{
//分别调用活跃Channel各自的回调函数
currentActiveChannel_ = channel;
currentActiveChannel_->handleEvent(pollReturnTime_);
}
currentActiveChannel_ = NULL;
eventHandling_ = false;
//处理从其它IO线程传过来的处理函数
doPendingFunctors();
}
LOG_TRACE << "EventLoop " << this << " stop looping";
looping_ = false;
}
void EventLoop::quit()
{
quit_ = true;
// There is a chance that loop() just executes while(!quit_) and exits,
// then EventLoop destructs, then we are accessing an invalid object.
// Can be fixed using mutex_ in both places.
if (!isInLoopThread())
{
//从其它IO线程终止当前线程的loop循环
wakeup();
}
}
void EventLoop::runInLoop(Functor cb)
{
if (isInLoopThread())
{
//如果当前调用线程为EventLoop的创建线程可以立即执行
cb();
}
else
{
//暂存到EventLoop的pendingFunctors_中
queueInLoop(std::move(cb));
}
}
void EventLoop::queueInLoop(Functor cb)
{
{
MutexLockGuard lock(mutex_);
pendingFunctors_.push_back(std::move(cb));
}
if (!isInLoopThread() || callingPendingFunctors_)
{
/*往EventLoop的创建线程的wakeupFd_写入8字节数据,唤醒该线程,
好让它立即处理pendingFunctors_中的函数队列
*/
wakeup();
}
}
size_t EventLoop::queueSize() const
{
MutexLockGuard lock(mutex_);
return pendingFunctors_.size();
}
//执行指定时间点的回调
TimerId EventLoop::runAt(Timestamp time, TimerCallback cb)
{
return timerQueue_->addTimer(std::move(cb), time, 0.0);
}
//执行(当前时间点+相对时间)应该执行的回调
TimerId EventLoop::runAfter(double delay, TimerCallback cb)
{
Timestamp time(addTime(Timestamp::now(), delay));
return runAt(time, std::move(cb));
}
//循环执行指定间隔时间的回调
TimerId EventLoop::runEvery(double interval, TimerCallback cb)
{
Timestamp time(addTime(Timestamp::now(), interval));
return timerQueue_->addTimer(std::move(cb), time, interval);
}
//取消某个定时
void EventLoop::cancel(TimerId timerId)
{
return timerQueue_->cancel(timerId);
}
//通知Poller更新Channel的监听事件
void EventLoop::updateChannel(Channel* channel)
{
assert(channel->ownerLoop() == this);
assertInLoopThread();
poller_->updateChannel(channel);
}
//通知Poller删除映射表中某个Channel,避免悬垂指针
void EventLoop::removeChannel(Channel* channel)
{
assert(channel->ownerLoop() == this);
assertInLoopThread();
if (eventHandling_)
{
assert(currentActiveChannel_ == channel ||
std::find(activeChannels_.begin(), activeChannels_.end(), channel) == activeChannels_.end());
}
poller_->removeChannel(channel);
}
//判断Poller监听的映射表是否含有传入的Channel
bool EventLoop::hasChannel(Channel* channel)
{
assert(channel->ownerLoop() == this);
assertInLoopThread();
return poller_->hasChannel(channel);
}
void EventLoop::abortNotInLoopThread()
{
LOG_FATAL << "EventLoop::abortNotInLoopThread - EventLoop " << this
<< " was created in threadId_ = " << threadId_
<< ", current thread id = " << CurrentThread::tid();
}
void EventLoop::wakeup()
{
//其它IO线程通过往wakeupFd_写入8字节唤醒该IO线程
uint64_t one = 1;
ssize_t n = sockets::write(wakeupFd_, &one, sizeof one);
if (n != sizeof one)
{
LOG_ERROR << "EventLoop::wakeup() writes " << n << " bytes instead of 8";
}
}
/*其它IO线程调用wakeup()时往该IO线程的wakeupFd_写入了8字节数据,当前IO线程立即从poll()
返回调用该读回调,因为该IO线程监听的wakeupFd_收到了其它IO线程刚刚写入的8字节数据*/
void EventLoop::handleRead()
{
uint64_t one = 1;
ssize_t n = sockets::read(wakeupFd_, &one, sizeof one);
if (n != sizeof one)
{
LOG_ERROR << "EventLoop::handleRead() reads " << n << " bytes instead of 8";
}
}
void EventLoop::doPendingFunctors()
{
std::vector<Functor> functors;
callingPendingFunctors_ = true;
{
//可能其它IO线程正在往pendingFunctors_写数据,因此要加锁
MutexLockGuard lock(mutex_);
functors.swap(pendingFunctors_);
}
//处理从其它IO线程传过来的函数,无需加锁
for (const Functor& functor : functors)
{
functor();
}
callingPendingFunctors_ = false;
}
void EventLoop::printActiveChannels() const
{
for (const Channel* channel : activeChannels_)
{
LOG_TRACE << "{" << channel->reventsToString() << "} ";
}
}