聊聊filezilla 3.7.2 事件处理机制

  filezilla 3.7.2 处理事件依赖于一个自己封装的事件处理器。名字叫event_loop类。 这个类在libfillezilla工程种。作为filezilla的一个动态库。因为这个处理器对于filezilla十分重要。所以借此机会学习以下。 

  event_loop 头文件在 libfilezilla工程目录\lib\libfilezilla\event_loop.hpp。 cpp在 libfilezilla\lib\event_loop.cpp。和event_loop关系密切的一个类是event_handler。位置与event_loop相同。 这个类是对event_loop的一个薄层封装。

  event_loop 支持两种,一种是事件类(event)的。另外一种是时间类(timer)的。

  对于怎么使用 event_loop,libfillezilla中有对应的例子。代码中也有简洁的类。以libfilezilla工程 demo_events 为例。demo_events工程 只有一个叫 events.cpp 的文件。代码十分简单。如下

 1 // Define a new event.
 2 // The event is uniquely identified via the incomplete my_event_type struct and
 3 // has two arguments: A string and a vector of ints.
 4 struct my_event_type;
 5 typedef fz::simple_event<my_event_type, std::string, std::vector<int>> my_event;
 6 
 7 // A simple event handler
 8 class handler final : public fz::event_handler
 9 {
10 public:
11     handler(fz::event_loop& l)
12         : fz::event_handler(l)
13     {}
14 
15     virtual ~handler()
16     {
17         // This _MUST_ be called to avoid a race so that operator()(fz::event_base const&) is not called on a partially destructed object.
18         remove_handler();
19     }
20 
21 private:
22     // The event loop calls this function for every event sent to this handler.
23     virtual void operator()(fz::event_base const& ev)
24     {
25         // Dispatch the event to the correct function.
26         fz::dispatch<my_event>(ev, this, &handler::on_my_event);
27     }
28 
29     void on_my_event(std::string const& s, std::vector<int> const& v)
30     {
31         std::cout << "Received event with text \"" << s << "\" and a vector with " << v.size() << " elements" << std::endl;
32 
33         // Signal the condition
34         fz::scoped_lock lock(m);
35         c.signal(lock);
36     }
37 };

 

 

可以看出,要使用event_loop类,需要实现自己的 event_handler类函数。在自己的event_handler类中需要做以下几件事。

  1 定义构造 析构函数

  2 定义自己 simple_event 的数据类型 以及这种数据类型的处理函数。

  3 定义自己仿函数(或者叫()重载运算符)。

 

调用也很简单,代码如下。  

 1 // Start an event loop
 2 fz::event_loop l;
 3 
 4 // Create a handler
 5 handler h(l);
 6 
 7 // Send an event to the handler
 8 h.send_event<my_event>("Hello World!", std::vector<int>{23, 42, 666});
 9 
10 // Wait until a signal from the worker thread
11 fz::scoped_lock lock(m);
12 c.wait(lock);  

  定义   fz::event_loop 类实例,用这个实例构造 handler 实例。调用 handler 的send_event函数函数。

  event_loop 类 依赖一个线程池,一个dqueue的队列。dqueue 用来存放发送过来的时间处理器,以及对应的参数。线程池可能是用来运行多个线程。来处理dqueue里面的数据。

  event_loop 成员函数都挺重要的。下面一个一个来分析。

  首先看构造函数。构造函数有三个。首先看无参构造函数 

 1 event_loop::event_loop()
 2     : sync_(false)
 3     , thread_(std::make_unique<thread>())
 4 {
 5     thread_->run([this] { entry(); });
 6 }

   这个构造函数采用默认异步方式。使用thread默认构造一个指向thread的智能指针。这个thread不是标准库的thread。而是filezilla自己实现的一个thread类。删除一些注释。代码如下

 1 class FZ_PUBLIC_SYMBOL thread final
 2 {
 3 public:
 4 #if defined(FZ_WINDOWS) && (defined(__MINGW32__) || defined(__MINGW64__))
 5     typedef uint32_t id;
 6 #else
 7     typedef std::thread::id id;
 8 #endif
 9 
10     thread() = default;
11 
12     ~thread();
13 
14     bool run(std::function<void()> && f);
15     void join();
16     bool joinable() const;
17     static id own_id();
18 
19 private:
20     class impl;
21     friend class impl;
22     impl* impl_{};
23 };

  成员主要 是一个impl的指针。还有一个线程ID。

  impl 类定义如下

class thread::impl final
{
public:
    std::thread t_;
};

  impl 类没有删减,只有一个 std::thread 的成员变量。让我们把注意力集中到thread 的run函数。这个比较重要,代码如下

 1 bool thread::run(std::function<void()> && f)
 2 {
 3     if (impl_) {
 4         return false;
 5     }
 6 
 7     try {
 8         impl_ = new impl;
 9         impl_->t_ = std::thread(std::move(f));
10     }
11     catch (std::exception const&) {
12         delete impl_;
13         impl_ = nullptr;
14     }
15 
16     return impl_ != nullptr;
17 }

  thread类 run成员函数参数是一个模板类std::function。使用的模板类型是个函数。这个函数是void 返回,无参的一个函数。

为啥使用右引用。这是因为传入的函数可能是右值。另外左值也可以转右值。使用右引用比较方便。run()函数逻辑也很简单。就是new 一个impl,

然后用传入函数,构造一个线程类。赋值给 impl的成员。再来分析event_loop的构造函数。参照上述的构造函数。

 

  thread_是唯一智能指针。用thread无参构造。然后指向thread 的run函数。run函数上面已经分析。现在看看传入参数。 [this] { entry(); }

这个函数是匿名函数。是 lambda表达式。不是很懂  lambda 表达式。匿名函数的执行体是就是thread类的entry函数。总的来说就是event_loop类构造时会构造内部成员,thread类智能指针。

然后调用thread 的run函数。run函数实际上是用匿名函数构造std::thread类。thread类在执行匿名函数时,会调用event_loop的 entry函数。

 

  再来看event_loop的另外两个构造函数, 首先看用thread_pool 构造的。

event_loop::event_loop(thread_pool & pool)
    : sync_(false)
{
    task_ = std::make_unique<async_task>(pool.spawn([this] { entry(); }));
}

  task_成员变量是 async_task 的一个智能指针。函数 pool.spawn 返回值一个 async_task的指针。看看spawn函数源码

 1 async_task thread_pool::spawn(std::function<void()> const& f)
 2 {
 3     async_task ret;
 4 
 5     if (f) {
 6         scoped_lock l(m_);
 7 
 8         pooled_thread_impl *t{};
 9         if (idle_.empty()) {
10             t = new pooled_thread_impl(*this);
11             if (!t->run()) {
12                 delete t;
13                 return ret;
14             }
15             threads_.push_back(t);
16         }
17         else {
18             t = idle_.back();
19             idle_.pop_back();
20         }
21 
22         ret.impl_ = new async_task_impl;
23         ret.impl_->thread_ = t;
24         t->task_ = ret.impl_;
25         t->f_ = f;
26         t->thread_cond_.signal(l);
27     }
28 
29     return ret;
30 }

  spawn 函数参数是一个函数模板类,使用的模板也是一个函数类型。void 返回,无参的函数。 async_task 类成员impl_定义如下。

async_task_impl* impl_{};

   async_task_impl 的定义如下。

1 1 class async_task_impl final
2 2 {
3 3 public:
4 4     pooled_thread_impl * thread_{};
5 5 };
 pooled_thread_impl类实现如下
 1 class pooled_thread_impl final
 2 {
 3 public:
 4     pooled_thread_impl(thread_pool & pool)
 5         : m_(pool.m_)
 6         , pool_(pool)
 7     {}
 8 
 9     virtual ~pooled_thread_impl()
10     {
11         thread_.join();
12     }
13 
14     bool run()
15     {
16         return thread_.run([this] { entry(); });
17     }
18 
19     virtual void entry() {
20         scoped_lock l(m_);
21         while (!quit_) {
22             thread_cond_.wait(l);
23 
24             if (f_) {
25                 l.unlock();
26                 f_();
27                 l.lock();
28                 task_ = nullptr;
29                 f_ = std::function<void()>();
30                 pool_.idle_.push_back(this);
31                 if (task_waiting_) {
32                     task_waiting_ = false;
33                     task_cond_.signal(l);
34                 }
35             }
36         }
37     }
38 
39     void quit(scoped_lock & l)
40     {
41         quit_ = true;
42         thread_cond_.signal(l);
43     }
44 
45     thread thread_;
46     async_task_impl* task_{};
47     std::function<void()> f_{};
48     mutex & m_;
49     condition thread_cond_;
50 
51     condition task_cond_;
52 
53     thread_pool& pool_;
54 
55     bool task_waiting_{};
56 private:
57     bool quit_{};
58 };

  重要的成员函数一个是run(),一个是entry()函数。run函数实现上述已描述过。结合 thread_pool::spawn 函数。传入一个函数。先会去判断idle是不是空。idle_是一个容器。定义如下:

std::vector<pooled_thread_impl*> idle_;

  如果是空,就是没有空闲的线程。就new 一个  pooled_thread_impl 类。然后执行成员函数run(), 这个成员run()执行的是thread类的成员函数run(),最终在某一个时机,thread线程会执行 

pooled_thread_impl类的entry函数。pooled_thread_impl类的entry函数,是一个简单的循环,它在等一个信号。等到以后就会执行,函数f_,然后把f_,task_置空。然后把当前类指针存入到idle_中。就可以重复利用。

只需要设置新的回调函数和信号。执行的这个f_就是spawn 的传入参数。传入的实参是 [this] { entry(); } 是匿名函数,是lambda 表达式。总之有些复杂,反正知道,某一时机,会执行event_loop类entry()就行。

 

  另外一个带参构造函数如下

1 event_loop::event_loop(event_loop::loop_option)
2     : sync_(false)
3 {
4 }

  带参构造的参数没有用,作用可能是用来区别 另外一个带  thread_pool 参数的构造函数。如果用这个构造函数来构造 event_loop ,显然是没法用的

这就需要调用者,手动调用另外一个函数。event_loop 的run成员函数,代码如下

1 void event_loop::run()
2 {
3     if (task_ || thread_ || thread_id_ != thread::id()) {
4         return;
5     }
6 
7     entry();
8 }

  非常简单的一个包装。前面是在判断一个成员变量是否有值。就是在判断是否采用了event_loop其他的两种构造方法。避免多次执行entry()方法。

看来这个entry方法十分重要。entry函数可以说是event_loop的核心处理过程。entry函数代码如下

 1 void event_loop::entry()
 2 {
 3     thread_id_ = thread::own_id();
 4 
 5     monotonic_clock now;
 6 
 7     scoped_lock l(sync_);
 8     while (!quit_) {
 9         if (process_timers(l, now)) {
10             continue;
11         }
12         if (process_event(l)) {
13             continue;
14         }
15 
16         // Nothing to do, now we wait
17         if (deadline_) {
18             cond_.wait(l, deadline_ - now);
19         }
20         else {
21             cond_.wait(l);
22         }
23     }
24 }

  event_loop 内部是一个循环,检测quit_成员变量有没有置。没有置的话·,开始处理。先处理timer类的事件。然后处理其他事件。最后就是等待信号。然后进入下次循环。

关键函数是 process_timers 和 process_event 函数。分别来看。

 1 bool event_loop::process_timers(scoped_lock & l, monotonic_clock & now)
 2 {
 3     if (!deadline_) {
 4         // There's no deadline
 5         return false;
 6     }
 7 
 8     now = monotonic_clock::now();
 9     if (now < deadline_) {
10         // Deadline has not yet expired
11         return false;
12     }
13 
14     // Update deadline_, stop at first expired timer
15     deadline_ = monotonic_clock();
16     auto it = timers_.begin();
17     for (; it != timers_.end(); ++it) {
18         if (!deadline_ || it->deadline_ < deadline_) {
19             if (it->deadline_ <= now) {
20                 break;
21             }
22             deadline_ = it->deadline_;
23         }
24     }
25 
26     if (it != timers_.end()) {
27         // 'it' is now expired
28         // deadline_ has been updated with prior timers
29         // go through remaining elements to update deadline_
30         for (auto it2 = std::next(it); it2 != timers_.end(); ++it2) {
31             if (!deadline_ || it2->deadline_ < deadline_) {
32                 deadline_ = it2->deadline_;
33             }
34         }
35 
36         event_handler *const handler = it->handler_;
37         auto const id = it->id_;
38 
39         // Update the expired timer
40         if (!it->interval_) {
41             timers_.erase(it);
42         }
43         else {
44             it->deadline_ = now + it->interval_;
45             if (!deadline_ || it->deadline_ < deadline_) {
46                 deadline_ = it->deadline_;
47             }
48         }
49 
50         // Call event handler
51         event_assert(!handler->removing_);
52 
53         active_handler_ = handler;
54 
55         l.unlock();
56         (*handler)(timer_event(id));
57         l.lock();
58 
59         active_handler_ = nullptr;
60 
61         return true;
62     }
63 
64     return false;
65 }

  process_timers 函数处理用到了一个timers_成员变量。timers_定义如下。

1 struct FZ_PRIVATE_SYMBOL timer_data final
2     {
3         event_handler* handler_{};
4         timer_id id_{};
5         monotonic_clock deadline_;
6         duration interval_{};
7     };
8 
9     typedef std::vector<timer_data> Timers;
10   Timers timers_;

  

  process_timers 函数先判断deadline_有否有效, 无效的话,就没有timer事件类。如果现在的时间都小于deadline_,就说明还没有timer事件类到期。

接下来遍历timers,找出第一个过期的timer事件。然后更新 deadline_。就是距离现在最近的timer的截止事件。然后开始处理这个过期的timer事件类。

timer事件类分两种,一种就是一次性的。另一种就是执行多次的,有时间间隔的。对于前一种,需要在timers容器上移除掉。另外一种需要更新deadline_。

timer 过期时间和 局部变量 deadline_的值。然后调用注册的handler处理函数处理这个timer。处理结束。

 

 然后看看event_loop::process_event函数。代码如下。
 1 bool event_loop::process_event(scoped_lock & l)
 2 {
 3     Events::value_type ev{};
 4 
 5     if (pending_events_.empty()) {
 6         return false;
 7     }
 8     ev = pending_events_.front();
 9     pending_events_.pop_front();
10 
11     event_assert(ev.first);
12     event_assert(ev.second);
13     event_assert(!ev.first->removing_);
14 
15     active_handler_ = ev.first;
16 
17     l.unlock();
18     (*ev.first)(*ev.second);
19     delete ev.second;
20     l.lock();
21 
22     active_handler_ = nullptr;
23 
24     return true;
25 }

    process_event 成员变量 panding_events_ 定义如下

1 typedef std::deque<std::pair<event_handler*, event_base*>> Events;
2 Events pending_events_;

    panding_events_ 是标准的std::deque队列。每个元素是一个键值对。第一个元素是 event_handler 事件处理器的指针。 第一个是event_base 事件类的指针。

process_event 函数从std::deque队列中取出一个事件然后调用事件处理器处理对应的事件。处理结束。
   process_event 使用(*ev.first)(*ev.second); process_timers 使用(*handler)(timer_event(id)); 来处理事件。无论前者还是后者,括号内都是类。那这代码能执行吗。
答案是能执行。这使用了()重载函数或者说是仿函数。可以参考最上面的的例子。从filezilla找一些例子来看。首先看CFileZillaEnginePrivate 类中一个例子。代码如下。
 1 void CFileZillaEnginePrivate::operator()(fz::event_base const& ev)
 2 {
 3     fz::scoped_lock lock(mutex_);
 4 
 5     fz::dispatch<CFileZillaEngineEvent, CCommandEvent, CAsyncRequestReplyEvent, fz::timer_event, CInvalidateCurrentWorkingDirEvent, options_changed_event>(ev, this,
 6         &CFileZillaEnginePrivate::OnEngineEvent,
 7         &CFileZillaEnginePrivate::OnCommandEvent,
 8         &CFileZillaEnginePrivate::OnSetAsyncRequestReplyEvent,
 9         &CFileZillaEnginePrivate::OnTimer,
10         &CFileZillaEnginePrivate::OnInvalidateCurrentWorkingDir,
11         &CFileZillaEnginePrivate::OnOptionsChanged
12         );
13 }

   传入参数是fz::event_base 的一个实例。然后加了一把锁。调用fz::dispatch函数。估计很多人看到 fz::dispatch 都吓到了。这么多参数。

不要慌,冷静一下,分析分析,也不难。看看 fz::dispatch 的实现。代码在libfilezilla工程目录\lib\libfilezilla\event_handler.hpp。代码如下

1 template<typename T, typename ... Ts, typename H, typename F, typename ... Fs>
2 bool dispatch(event_base const& ev, H* h, F&& f, Fs&& ... fs)
3 {
4     if (dispatch<T>(ev, h, std::forward<F>(f))) {
5         return true;
6     }
7 
8     return dispatch<Ts...>(ev, h, std::forward<Fs>(fs)...);
9 }
  dispatch函数使用了5个模板参数第一个模板参数T 对应的调用者CFileZillaEngineEvent的类。第二个是变参模板就是可以有1个或多个模板类对用调用者 CCommandEvent 到options_changed_event。
ev 是调用dispath传入具体的一个event_base实例。H对应this 指针 F对应&CFileZillaEnginePrivate::OnEngineEvent 处理函数。Fs对应 &CFileZillaEnginePrivate::OnCommandEvent 到
&CFileZillaEnginePrivate::OnOptionsChanged 处理函数。先按照 CFileZillaEngineEvent 来类型,调用具体的处理函数处理,如果处理了,就返回。没处理,就再递归调用自己,直到找到一个能处理传入
event_base 的处理器,然后调用处理。

  接下来看看dispatch函数如果判断类模板T,传入参数ev类二者是否匹配。是否该调用对应的对应函数。代码如下
 1 template<typename T, typename H, typename F>
 2 bool dispatch(event_base const& ev, H* h, F&& f)
 3 {
 4     bool const same = same_type<T>(ev);
 5     if (same) {
 6         T const* e = static_cast<T const*>(&ev);
 7         apply(h, std::forward<F>(f), e->v_);
 8     }
 9     return same;
10 }

   same_type 实现如下。

1 template<typename T>
2 bool same_type(event_base const& ev)
3 {
4     return ev.derived_type() == T::type();
5 }

  简单来说就是判断两个类型是否一致。一致的话调用相对应的处理函数。apply 具体实现就不贴了。

另外一个相关的dispatch函数在这里贴一下。

 1 template<typename T, typename F>
 2 bool dispatch(event_base const& ev, F&& f)
 3 {
 4     bool const same = same_type<T>(ev);
 5     if (same) {
 6         T const* e = static_cast<T const*>(&ev);
 7         std::apply(std::forward<F>(f), e->v_);
 8     }
 9     return same;
10 }
  这两个dispath 函数 使用的模板参数不同,原因在于,处理函数是否属于类。属于类的成员函数的应该使用三个模板参数的。否则应两个模板参数的。

  上面介绍的其他事件处理类的仿函数。现在在看一个事件处理的仿函数。以CControlSocket 类中仿函数以为。
1 void CControlSocket::operator()(fz::event_base const& ev)
2 {
3     fz::dispatch<fz::timer_event, CObtainLockEvent>(ev, this,
4         &CControlSocket::OnTimer,
5         &CControlSocket::OnObtainLock);
6 }

  可以看到和其他事件处理仿函数十分相似。就不再描述。  


  以上介绍的是event_loop是怎么处理timer类事件和其他事件流程。

  现在结束怎么在event添加事件。因为 timer类事件和 其他事件类使用的容器不一样。处理机制也不太相同。所以二者添加方式也不同。
  
  先看看时间类事件是怎么添加的。代码如下
  
 1 timer_id event_loop::add_timer(event_handler* handler, duration const& interval, bool one_shot)
 2 {
 3     timer_data d;
 4     d.handler_ = handler;
 5     if (!one_shot) {
 6         d.interval_ = interval;
 7     }
 8     d.deadline_ = monotonic_clock::now() + interval;
 9 
10     scoped_lock lock(sync_);
11     if (!handler->removing_) {
12         d.id_ = ++next_timer_id_; // 64bit, can this really ever overflow?
13 
14         timers_.emplace_back(d);
15         if (!deadline_ || d.deadline_ < deadline_) {
16             // Our new time is the next timer to trigger
17             deadline_ = d.deadline_;
18             cond_.signal(lock);
19         }
20     }
21     return d.id_;
22 }

  整体逻辑比较简单。传入参数 一个处理器的类。一个间隔类interval,还有一个参数one_shot,是不是执行一次。

如果是一次的话,就忽略传入的 interval。然后就是计算终止时间,置信号。然后返回一个timer_id。这个返回值有什么用呢。

用户可以保存起来。然后调用 event_loop的 stop_timer成员函数。取消对应的timer 事件处理。

  event_loop的 stop_timer代码如下:  

 1 void event_loop::stop_timer(timer_id id)
 2 {
 3     if (id) {
 4         scoped_lock lock(sync_);
 5         for (auto it = timers_.begin(); it != timers_.end(); ++it) {
 6             if (it->id_ == id) {
 7                 timers_.erase(it);
 8                 if (timers_.empty()) {
 9                     deadline_ = monotonic_clock();
10                 }
11                 break;
12             }
13         }
14     }
15 }

 传入参数是add_timer函数返回值。实现就是再timers对应中移除掉指定timer_id 的timer类事件。

 

  接下来看看其他事件处理添加逻辑。代码如下  

 1 void event_loop::send_event(event_handler* handler, event_base* evt)
 2 {
 3     event_assert(handler);
 4     event_assert(evt);
 5 
 6     {
 7         scoped_lock lock(sync_);
 8         if (!handler->removing_) {
 9             if (pending_events_.empty()) {
10                 cond_.signal(lock);
11             }
12             pending_events_.emplace_back(handler, evt);
13             return;
14         }
15     }
16 
17     delete evt;
18 }

  可以看到 sent_event 传入参数一个event_handler 的指针。一个event_base 的实例。先去判断pending_events_队列是否是空,空的话就置信号。然后插入handler 和 evt 。

如果不是空的话,只有插入队列的操作。其他事件的添加使用实例可以参考本篇开头例子。

 

  event_loop 中对于其他事件类有一个专门的处理函数。filter_events 函数。看函数名字就知道这就是一个其他事件过滤函数。代码实现如下

 1 void event_loop::filter_events(std::function<bool(Events::value_type &)> const& filter)
 2 {
 3     scoped_lock l(sync_);
 4 
 5     pending_events_.erase(
 6         std::remove_if(pending_events_.begin(), pending_events_.end(),
 7             [&](Events::value_type & v) {
 8                 bool const remove = filter(v);
 9                 if (remove) {
10                     delete v.second;
11                 }
12                 return remove;
13             }
14         ),
15         pending_events_.end()
16     );
17 }

  filter_events 函数传入参数是一个 std::function模板类 使用的模板参数是一个函数。这个函数的返回值是bool 参数类型是 Events::value_type 引用类型。filter能代表传入的函数。

pending_events_.erase 内嵌套一个std::remove_if函数。从pending_event_第一个元素到最后一个元素。使用匿名函数。你们函数内部使用传入参数的回调来判断事件是不是需要移除。需要移除的,析构掉第二个元素类。
然后将这个元素移动到pending_events_末尾。经过迭代,pengding_events_末尾都是需要删除的元素。remove_if返回一个需要删除元素的前一个元素。然后使用erase方法删除这些元素。
下面这个代码是 CSftpControlSocket::DoClose调用的部分代码。
 1 auto threadEventsFilter = [&](fz::event_loop::Events::value_type const& ev) -> bool {
 2             if (ev.first != this) {
 3                 return false;
 4             }
 5             else if (ev.second->derived_type() == CSftpEvent::type() || ev.second->derived_type() == CTerminateEvent::type()) {
 6                 return true;
 7             }
 8             return false;
 9         };
10 
11         event_loop_.filter_events(threadEventsFilter);

  可以看到 上面这个过滤器过滤的是类型是 CSftpEvent::type类型 或者是 CTerminateEvent::type 类型的。

 timer事件类用stop_timer移除指定的timer事件。其他事件类可以用filter_events 来过滤一些特别的事件。除此以外,event_loop还有一个更通用的函数可以用来移除一些特定的处理器。
这个函数就是remove_handler,代码如下:
 1 void event_loop::remove_handler(event_handler* handler)
 2 {
 3     scoped_lock l(sync_);
 4 
 5     handler->removing_ = true;
 6 
 7     pending_events_.erase(
 8         std::remove_if(pending_events_.begin(), pending_events_.end(),
 9             [&](Events::value_type const& v) {
10                 if (v.first == handler) {
11                     delete v.second;
12                 }
13                 return v.first == handler;
14             }
15         ),
16         pending_events_.end()
17     );
18 
19     timers_.erase(
20         std::remove_if(timers_.begin(), timers_.end(),
21             [&](timer_data const& v) {
22                 return v.handler_ == handler;
23             }
24         ),
25         timers_.end()
26     );
27     if (timers_.empty()) {
28         deadline_ = monotonic_clock();
29     }
30 
31     if (active_handler_ == handler) {
32         if (thread::own_id() != thread_id_) {
33             while (active_handler_ == handler) {
34                 l.unlock();
35                 yield();
36                 l.lock();
37             }
38         }
39     }
40 }

   实现就是在两个容易中遍历,删除符合条件的handler的事件。

   event_loop类除了以上的函数以外,还有一个 stop函数。代码如下  

 1 void event_loop::stop(bool join)
 2 {
 3     {
 4         scoped_lock l(sync_);
 5         quit_ = true;
 6         cond_.signal(l);
 7     }
 8 
 9     if (join) {
10         thread_.reset();
11         task_.reset();
12 
13         scoped_lock lock(sync_);
14         for (auto & v : pending_events_) {
15             delete v.second;
16         }
17         pending_events_.clear();
18 
19         timers_.clear();
20         deadline_ = monotonic_clock();
21     }
22 }

  stop函数设置退出标准,重置了信号。随便就遍历pending_events_,析构第二个元素。删除元素。清空timers_容器。

  到此位置,event_loop类基本已经介绍完成了。

  简单回顾一下,做个总结。

  eventloop有三种构造方式,无参构造函数,带thread_pool 类的构造,以及 带event_loop::loop_option 参数构造。前面两种构造时会调用event_loop的entry函数。

entry函数线程的执行体,处理timer事件类和 其他的事件类,与时间无关的事件。使用后者构造,需要手动调用run()函数。run()中会调用entry函数。

entry函数执行以后,就可以添加事件了。timer类的事件用add_timer类函数其他事件用send_event函数。timer类事件移除调用stop_timer函数。其他事件类调用event_filter来移除一些事件。

二者都可以用remove_handler来 移除的特定的handler 处理的事件。想要结束处理的话,就调用stop函数。清理线程,清理事件。

  整体上就是这样,希望有所收获。

 

  参考:https://www.cplusplus.com/reference/algorithm/remove_if/

      https://blog.csdn.net/kfling/article/details/80187847 

posted @ 2021-06-22 19:38  _SmailWind  阅读(156)  评论(0)    收藏  举报