最近在研究muduo源代码,因为之前的项目内部的逻辑与muduo类似,不过使用的是libevent完成内核的构造,muduo使用了自己写的poll和epoll方式完成内部的io复用。之前的项目与muduo使用的策略一致,使用了主线程专门用于接收tcp连接,连接后的connection发送到多个子线程中来支持高并发。
eventloop.h
这个类是muduo的核心,头文件如下(已做注释):
///
/// 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.
/// 只能在创建当前实例的线程执行loop函数
void loop();
/// Quits loop.
/// 使用共享指针的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.
/// 在 loop 中执行函数,线程安全
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
///
/// 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.
/// 经过delay的延时后调用回调函数
TimerId runAfter(double delay, TimerCallback cb);
///
/// Runs callback every @c interval seconds.
/// Safe to call from other threads.
/// 每过interval时间后调用回调函数
TimerId runEvery(double interval, TimerCallback cb);
///
/// Cancels the timer.
/// Safe to call from other threads.
/// 取消时间器的回调函数
void cancel(TimerId timerId);
// internal usage
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();
}
}
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; }
// 获得context
const boost::any& getContext() const
{ return context_; }
// 获得非常量的context
boost::any* getMutableContext()
{ return &context_; }
// 获得当前线程的eventloop
static EventLoop* getEventLoopOfCurrentThread();
private:
void abortNotInLoopThread(); // 退出程序
void handleRead(); // waked up
void doPendingFunctors();
void printActiveChannels() const; // DEBUG
typedef std::vector<Channel*> ChannelList; // 用于存储channel
bool looping_; /* atomic */
std::atomic<bool> quit_; // 判断是否离开loop
bool eventHandling_; /* atomic */
bool callingPendingFunctors_; /* atomic */
int64_t iteration_; // 记录 loop 循环的次数
const pid_t threadId_;
Timestamp pollReturnTime_; // poll返回时间戳
std::unique_ptr<Poller> poller_;
std::unique_ptr<TimerQueue> timerQueue_; // 时间队列
int wakeupFd_; // 唤醒fd,使用 eventfd() 创建
// unlike in TimerQueue, which is an internal class,
// we don't expose Channel to client.
std::unique_ptr<Channel> wakeupChannel_; // 唤醒fd 的 channel
boost::any context_;
// scratch variables
ChannelList activeChannels_; // 激活的 channel
Channel* currentActiveChannel_; // 当前的活动 channel
mutable MutexLock mutex_;
std::vector<Functor> pendingFunctors_ GUARDED_BY(mutex_); // 挂起的 函数体
};
成员变量std::unique_ptr poller_
它的实现有两个分别是poll和epoll,类关系如下图:
其中poller_使用了唯一智能指针创建,因为一个EventLoop只能使用一种Poller内核。Poller使用的函数如下:
pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_);
poller_->updateChannel(channel);
poller_->removeChannel(channel);
poller_->hasChannel(channel);
成员变量wakeupFd_
int wakeupFd_;
std::unique_ptr wakeupChannel_;
以上两个变量完成了对于EventLoop的唤醒操作。
当需要唤醒EventLoop时只需要写入wakeupFd_即可。
在构造函数中使用
wakeupFd_(createEventfd()), // 创建唤醒 fd
wakeupChannel_(new Channel(this, wakeupFd_)),
创建。
wakeupChannel_为wakeupFd_绑定了读取回调函数,在EventLoop函数的析构函数中,关闭了所有的监听事件并close(wakeupFd_)
成员变量 ChannelList
typedef std::vector<Channel*> ChannelList;
ChannelList activeChannels_; // 激活的 channel 链表
该vector用来存储 poller_ io复用后激活的所有事件。