当前位置:   article > 正文

libevent源码分析之事件激活_libevent 在线程中激活事件

libevent 在线程中激活事件
之前了解过了多种事件, 但都是从是什么, 如何理解, 如何存储的方面讲解的, 这里就集中的谈谈事件的激活
了解的事件有, 基本IO事件, 信号事件, 超时事件(只是事件可以是单纯的超时事件, 也可以是其他事件带有定时器, 因此不会特意看超时事件)
以及不同优先级事件的处理

虽然IO事件与信号事件是截然不同的处理方式, 但他们的事件处理程序都是处测在同一个event_base中的, 所以想要了解如何处理这两种事件, 关注的点就是event_base的dispatch, 之后蔓延开来
无论是 event_base_dispatch() 还是 event_loop() 都是调用的event_base_loop()


注意:

整篇文章是以event_base_loop()为核心, 通过分析其中调用的函数来对整个执行过程进行全面的了解
所以, 但凡遇到函数了, 在文章后面部分都会对函数进行分析, 阅读方式是先对event_base_loop函数有个粗略的了解, 之后从头开始, 分析其中详细内容
分析之前, 我自身对其中几个地方是存在疑惑的, 比如线程,对于线程锁、条件变量的设计经常会卡住, 甚至一直搞不明白, 所以遇到锁,条件变量就跳过, 当作是单线程来看把

大纲:
  1. //在event.c中, 这里面省略了些许不相关代码
  2. int
  3. event_base_loop(struct event_base *base, int flags)
  4. {
  5. /* Grab the lock. We will release it inside evsel.dispatch, and again
  6. * as we invoke user callbacks. */
  7. //获取锁, 且是在调用evsel->dispatch() 前释放的锁, 需要配合evsel->dispatch的多线程逻辑
  8. EVBASE_ACQUIRE_LOCK(base, th_base_lock);
  9. //一个base在一个时间段内只能被一个线程运行
  10. if (base->running_loop) {
  11. ... ...(error)
  12. }
  13. //如果在event_base_dispatch之前, 有对信号的event_add调用, 那么 base->sig.ev_signal_added就会为1
  14. //反之, 如果用户没有要求关注任何信号, 那么这个if就会被跳过了
  15. //这个函数的目的在于为libevent的信号模块设置全局变量, 比如指定接收信号的base是哪个, 要监听几个信号, IO复用中信号事件的管道一端是哪个
  16. if (base->sig.ev_signal_added && base->sig.ev_n_signals_added)
  17. evsig_set_base(base);
  18. done = 0;
  19. base->event_gotterm = base->event_break = 0;
  20. while (!done) {
  21. base->event_continue = 0;
  22. /* Terminate the loop if we have been asked to */
  23. if (base->event_gotterm) {
  24. break;
  25. }
  26. if (base->event_break) {
  27. break;
  28. }
  29. timeout_correct(base, &tv);
  30. tv_p = &tv;
  31. //如果此时没有已经激活的事件需要处理(如果对这里有疑惑, 那么还请继续往下看, 先假设是第一次启动base), 并且base不是非阻塞的, 此时就要为base指定一个超时时间
  32. //timeout_next函数就是用来指定新的超时时间的, 看此函数下面的解析
  33. if (!N_ACTIVE_CALLBACKS(base) && !(flags & EVLOOP_NONBLOCK)) {
  34. timeout_next(base, &tv_p);
  35. } else {
  36. /*
  37. * if we have active events, we just poll new events
  38. * without waiting.
  39. */
  40. evutil_timerclear(&tv);
  41. }
  42. /* If we have no events, we just exit */
  43. //没有事件, 且没有激活事件,说明没有事情要base做,即可退出
  44. if (!event_haveevents(base) && !N_ACTIVE_CALLBACKS(base)) {
  45. event_debug(("%s: no events registered.", __func__));
  46. retval = 1;
  47. goto done;
  48. }
  49. /* update last old time */
  50. gettime(base, &base->event_tv);
  51. clear_time_cache(base);
  52. //这就是核心的IO复用函数调用, 就涉及我们要讨论的处理激活事件的过程
  53. //所以看到这里, 我希望可以转到evsel->dispatch函数中去了解其中的内容, 接着继续回到这里
  54. //概括性的来说, evsel->dispatch的目的是在得知有数据要来后, 将对应的文件描述符激活
  55. res = evsel->dispatch(base, tv_p);
  56. if (res == -1) {
  57. ... ...(error)
  58. goto done;
  59. }
  60. upd
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/代码探险家/article/detail/742771
推荐阅读
  

闽ICP备14008679号