这里会忽略用于测试,判断当前线程,返回数据成员的函数,省略标志位成员变量。
不区分public与private。
class EventLoop
{
/**********Function Memeber**************/
typedef boost::function<void()> Functor;
EventLoop();
~EventLoop();
//general
void loop();
void quit();
//timers
void runAt(const Timestamp& time, const TimerCallback &cb);
void runAfter(double delay, const TimerCallback &cb);
void runEvery(double interval, const TimerCallback &cb);
//Channel
void updateChannel(Channel* channel);
void removeChannel(Channel* channel);
//wakeup
void wakeup();
void handleRead();
void runInLoop(const Functor& cb);
void queueInLoop(const Functor& cb);
void doPendingFunctors();
int createEventfd();
/*************Data Member********************/
typedef std::vector<Channel*> ChannelList;
//general
boost::scoped_ptr<Poller> poller;
boost::scoped_ptr<TimerQueue> timerQueue;
//channel
ChannelList activeChannels;
channel* currentActiveChannel;
//wakeup
int wakeupFd;
boost::scoped_ptr<Channel> wakeupChannel;
MutexLock mutex;
std::vector<Functor> pendingFunctors;
};
需要特别说明的就是有关wakeup的东西
(1)wakeupFd用createEventfd()建立
用于表示此loop的fd,并且为了放入poller,专门用一个wakeupChannel来作为watcher。
(2)这整个wakeup相关的data与function,目的就是能够在线程之间调配任务,且在不加锁的情况下保证线程安全性。
runInLoop()保证放入其中的callback函数都由IO线程(及loop所在线程)调用,因为其他的线程可以通过持有loop而调用runInLoop。
runInLoop()首先判断当前线程是否为IO线程
①如果是,则可以直接调用callback
②如果不是,通过调用queueInLoop(),将这个callback放入pendingFunctors这个vector中,然后调用wakeup()向wakeupFd代表的事件(IO线程)发送一个字节,将其唤醒。这样唤醒后,loop线程的loop()就会在处理的时候通过调用doPendingFunctors(),调用pendingFunctors里面的callback。
综上,通过①,②保证了放入runInLoop()的callback都是由IO线程调用的。
从而保证了不用锁线程安全性。
(3)最后省的mutex以及handleRead的作用
①mutex
作为开放给其他所有线程的数据结构,pendingFunctors,其他线程可以同时向这个vector里面通过runInLoop()增加callback,
为了确保并发安全性对它的操作加个锁就是了。
②handleRead
通过wakeup()告知IO线程有pendingFunctors需要处理了,是通过poll来实现通知的,poll会对所有发生了关注事件的channel遍历处理。
而我们的wakeupChannel专门是通过socket,write一个字节来通知的,这里你放进去的callback可以将其read了,使其wakeupFd状态重新被监听。
然而真正的处理pendingFunctors是放在处理完所有的的activechannel的callback之后再调用doPendingFunctors()来处理的(代码见EventLoop::loop())。