在看了001 - inner_pre 之后发现就实现了三个函数,其中两个是非常关键的函数EventAdd和EventDel,接下来的EventWatcher这个类中将会用到这两个函数,看一下 EventWatcher这个类声明。
class EventLoop;
class EVPP_EXPORT EventWatcher {
public:
typedef std::function<void()> Handler;
virtual ~EventWatcher();
bool Init();
// @note It MUST be called in the event thread.
void Cancel();
// @brief :
// @param[IN] const Handler& cb - The callback which will be called when this event is canceled.
// @return void -
void SetCancelCallback(const Handler& cb);
void ClearHandler() { handler_ = Handler(); }
protected:
// @note It MUST be called in the event thread.
// @param timeout the maximum amount of time to wait for the event, or 0 to wait forever
bool Watch(Duration timeout);
protected:
EventWatcher(struct event_base* evbase, const Handler& handler);
EventWatcher(struct event_base* evbase, Handler&& handler);
void Close();
void FreeEvent();
virtual bool DoInit() = 0;
virtual void DoClose() {}
protected:
struct event* event_;
struct event_base* evbase_;
bool attached_;
Handler handler_;
Handler cancel_callback_;
};
总体的看了一下, 发现EventWatcher这个类,提供了一个自定义类型 Hanlder,一些公共的方法,保护方法和一些保护的成员变量。看到了保护方法里有两个virtual 开头的虚函数声明,应该知道这个应该作为抽象父类使用。
下面仔细分析一下这个类:
前置声明了一个类
EventLoop
, 后面会看到EventLoop
他在这个类中的作用。类的两个构造函数
protected:
EventWatcher(struct event_base* evbase, const Handler& handler);
EventWatcher(struct event_base* evbase, Handler&& handler);
具体的实现:
EventWatcher::EventWatcher(struct event_base *evbase, const Handler &handler)
: evbase_(evbase), attached_(false), handler_(handler) {
event_ = new event;
memset(event_, 0, sizeof(struct event));
}
EventWatcher::EventWatcher(struct event_base *evbase, Handler &&handler)
: evbase_(evbase), attached_(false), handler_(std::move(handler)) {
event_ = new event;
memset(event_, 0, sizeof(struct event));
}
就是将自己的成员变量进行初始化, 特别要注意的是,不管是调用了那一个构造函数,在构造函数里都把event_
成员变量new
了出来,而且进行了memset
。
- 虚析构函数
EventWatcher::~EventWatcher() {
FreeEvent();
Close();
}
在析构函数中主要是完成成员变量event_的释放FreeEvent()
和后续的关闭动作Close()
。
-
FreeEvent()
方法
void EventWatcher::FreeEvent() {
if (event_) {
if (attached_) {
EventDel(event_);
attached_ = false;
}
delete (event_);
event_ = nullptr;
}
}
从上面的实现方法可以看到,如果event_
是非空指针,并且已经被安装到了evbase_
上,就调用EventDel
函数将其从evbase_
进行删除。并将attached_
成员变量设置成false
。
后续释放了event_
的资源,并且赋值nullptr
。
-
Close()
方法
void EventWatcher::Close() { DoClose(); }
调用了DoClose()
方法, 这个DoClose()
是个需函数有自己默认实现,后续的子类也可以重写此方法。
-
Init()
方法
bool EventWatcher::Init() {
if (!DoInit()) {
goto failed;
}
::event_base_set(evbase_, event_);
return true;
failed:
Close();
return false;
}
在Init()
中在调用了自己的方法 DoInit()
, 如果 DoInit()
成功,会将自己之前new
出来的成员变量event_
设置一个event base。 调用了一个libevent
的方法::event_base_set(evbase_, event_)
, 将event_
绑定到evbase
上。
DoInit()
是一个纯虚函数,有后续的子类实现不同类型的event
。这个是重点。
-
Cancel()
方法
void EventWatcher::Cancel() {
assert(event_);
FreeEvent();
if (cancel_callback_) {
cancel_callback_();
cancel_callback_ = Handler();
}
}
在Cancel()
中 调用了FreeEvent()
方法释放event_
, 如果有cancel_callback_
,就执行cancel_callback_()
,后续将cancel_callback_
赋值成空。
- 辅助的方法
void SetCancelCallback(const Handler& cb);
void ClearHandler() { handler_ = Handler(); }
SetCancelCallback
用于成员变量 cancel_callback_
的赋值, 在Cancel()
被调用。
ClearHandler
清除成员变量 handler_
。
-
Watch()
方法
bool EventWatcher::Watch(Duration timeout) {
struct timeval tv;
struct timeval *timeoutval = nullptr;
if (timeout.Nanoseconds() > 0) {
timeout.To(&tv);
timeoutval = &tv;
}
if (attached_) {
// When InvokerTimer::periodic_ == true, EventWatcher::Watch will be called
// many times so we need to remove it from event_base before we add it into
// event_base
if (EventDel(event_) != 0) {
LOG_ERROR << "event_del failed. fd=" << this->event_->ev_fd
<< " event_=" << event_;
// TODO how to deal with it when failed?
}
attached_ = false;
}
assert(!attached_);
if (EventAdd(event_, timeoutval) != 0) {
LOG_ERROR << "event_add failed. fd=" << this->event_->ev_fd
<< " event_=" << event_;
return false;
}
attached_ = true;
return true;
}
Watch()
方法是这个类的精髓所在,前面所做的Init()
都是为了这个方法服务,经过了Init()
, 成员变量event_
应该有了自己的事件类型,通过if (EventAdd(event_, timeoutval) != 0) {
这一句,将event_
安装到了evbase_
上,如果安装成功,将成员变量attached_
赋值true
。 注意的是前面Init()
中用了一个词语叫绑定
只是说event和base之间有关系,base运行还不能带有这个事件触发器, 这里用了安装
,base运行就可以带有这个触发的触发器。
可以想一下这个类的用例流程:
- 先调用
Init()
,将成员变量event_
进行相应事件的初始化。 - 在调用
Watch()
,将成员变量安装到evbase_
上。