Muduo学习笔记(一) 什么都不做的EventLoop

EventLoop

EventLoop的基本接口包括构造、析构、loop()。

One Loop Per Thread 一个线程只有一个EventLoop对象、如果当前线程创建了其他 EventLoop对象,则终止程序.

CurrentThread

CurrentThread 通过__thread 关键字和系统调用syscall() 保存获取线程的的pid(不通于线程tid,tid属于进程,进程内唯一,线程pid属于内核).

  1. #ifndef _CURRENT_THREAD
  2. #define _CURRENT_THREAD
  3. #include <stdint.h>
  4. #include <stdio.h>
  5. #include <sys/syscall.h>
  6. #include <pthread.h>
  7. #include <unistd.h>
  8. namespace CurrentThread
  9. {
  10. // internal
  11. extern __thread int t_cachedTid;
  12. extern __thread char t_tidString[32];
  13. extern __thread int t_tidStringLength;
  14. extern __thread const char* t_threadName;
  15. inline int tid()
  16. {
  17. if (__builtin_expect(t_cachedTid == 0, 0))
  18. {
  19. if (t_cachedTid == 0)
  20. {
  21. t_cachedTid = static_cast<pid_t>(::syscall(SYS_gettid));
  22. t_tidStringLength = snprintf(t_tidString, sizeof t_tidString, "%5d ", t_cachedTid);
  23. }
  24. }
  25. return t_cachedTid;
  26. }
  27. inline const char* tidString() // for logging
  28. {
  29. return t_tidString;
  30. }
  31. inline int tidStringLength() // for logging
  32. {
  33. return t_tidStringLength;
  34. }
  35. inline const char* name()
  36. {
  37. return t_threadName;
  38. }
  39. }
  40. #endif
  41. //CurrentThread.cpp
  42. #include "CurrentThread.hh"
  43. namespace CurrentThread
  44. {
  45. __thread int t_cachedTid = 0;
  46. __thread char t_tidString[32];
  47. __thread int t_tidStringLength = 6;
  48. __thread const char* t_threadName = "unknown";
  49. }

getEventLoopOfCurrentThread

每个线程至多有一个EventLoop对象,那么我们通过static 成员函数getEventLoopOfCurrentThread() 返回此对象.

  1. EventLoop* EventLoop::getEventLoopOfCurrentThread()
  2. {
  3. return t_loopInThisThread;
  4. }

EventLoop 源代码

  1. #ifndef NET_EVENTLOOP_H
  2. #define NET_EVENTLOOP_H
  3. #include "CurrentThread.hh"
  4. class EventLoop
  5. {
  6. public:
  7. EventLoop();
  8. ~EventLoop();
  9. void loop();
  10. void assertInLoopThread()
  11. {
  12. if(!isInloopThread())
  13. {
  14. abortNotInLoopThread();
  15. }
  16. }
  17. bool isInloopThread() const {return m_threadId == CurrentThread::tid(); }
  18. static EventLoop* getEventLoopOfCurrentThread();
  19. private:
  20. EventLoop& operator=(const EventLoop&);
  21. EventLoop(const EventLoop&);
  22. void abortNotInLoopThread();
  23. bool m_looping;
  24. const pid_t m_threadId;
  25. };
  26. #endif
  27. // EventLoop.cpp
  28. #include "EventLoop.hh"
  29. #include "Logger.hh"
  30. #include <assert.h>
  31. #include <poll.h>
  32. __thread EventLoop* t_loopInThisThread = 0;
  33. EventLoop::EventLoop()
  34. :m_looping(false),
  35. m_threadId(CurrentThread::tid())
  36. {
  37. LOG_TRACE << "EventLoop Create " << this << " in thread " << m_threadId;
  38. if(t_loopInThisThread)
  39. { //每个线程只有一个EventLoop对象 , 如果当前线程创建了其他 EventLoop对象,则终止程序.
  40. LOG_FATAL << "Anthor EventLoop " << t_loopInThisThread
  41. << " exists in this thread " << m_threadId;
  42. }
  43. else
  44. {
  45. t_loopInThisThread = this;
  46. }
  47. }
  48. EventLoop::~EventLoop()
  49. {
  50. assert(!m_looping);
  51. t_loopInThisThread = NULL;
  52. }
  53. void EventLoop::loop()
  54. {
  55. assert(!m_looping);
  56. assertInLoopThread();
  57. m_looping = true;
  58. LOG_TRACE << "EventLoop " << this << " start loopig";
  59. ::poll(NULL, 0, 3*1000);
  60. LOG_TRACE << "EventLoop " << this << " stop loopig";
  61. m_looping = false;
  62. }
  63. void EventLoop::abortNotInLoopThread()
  64. {
  65. LOG_FATAL << "EventLoop::abortNotInLoopThread - EventLoop " << this
  66. << " was created in threadId_ = " << m_threadId
  67. << ", current thread id = " << CurrentThread::tid();
  68. }
  69. EventLoop* EventLoop::getEventLoopOfCurrentThread()
  70. {
  71. return t_loopInThisThread;
  72. }

测试程序

test1

正确的逻辑.

  1. #include <errno.h>
  2. #include "EventLoop.hh"
  3. #include <thread>
  4. int main()
  5. {
  6. EventLoop testloop;
  7. testloop.loop();
  8. return 0;
  9. }
  1. ./test.out
  2. 2018-10-25 20:01:03.287601 [TRACE] [EventLoop.cpp:12] [EventLoop] EventLoop Create 0x7FFF7B1E2780 in thread 2086
  3. 2018-10-25 20:01:03.287750 [TRACE] [EventLoop.cpp:36] [loop] EventLoop 0x7FFF7B1E2780 start loopig
  4. 2018-10-25 20:01:06.291622 [TRACE] [EventLoop.cpp:40] [loop] EventLoop 0x7FFF7B1E2780 stop loopig

test2

企图在当前线程启用其他线程创建的EventLoop对象

  1. #include <errno.h>
  2. #include "EventLoop.hh"
  3. #include <thread>
  4. EventLoop* g_loop;
  5. void test()
  6. {
  7. g_loop->loop();
  8. }
  9. int main()
  10. {
  11. EventLoop testloop;
  12. //testloop.loop();
  13. g_loop = &testloop;
  14. std::thread test_thread(test);
  15. test_thread.join();
  16. return 0;
  17. }
  1. ./test.out
  2. 2018-10-25 20:05:49.618701 [TRACE] [EventLoop.cpp:12] [EventLoop] EventLoop Create 0x7FFCA55A35F0 in thread 2114
  3. 2018-10-25 20:05:49.619057 [FATAL] [EventLoop.cpp:47] EventLoop::abortNotInLoopThread - EventLoop 0x7FFCA55A35F0 was created in threadId_ = 2114, current thread id = 2115
  4. Aborted (core dumped)

Muduo学习笔记(一) 什么都不做的EventLoop的更多相关文章

  1. muduo学习笔记(二)Reactor关键结构

    目录 muduo学习笔记(二)Reactor关键结构 Reactor简述 什么是Reactor Reactor模型的优缺点 poll简述 poll使用样例 muduo Reactor关键结构 Chan ...

  2. muduo学习笔记(六) 多线程的TcpServer

    目录 前言 多线程TcpServer EventLoopThreadPool 线程池设计模式 muduo中的使用 连接的建立.消息.销毁 on_connection on_message on_clo ...

  3. Python学习笔记:Flask-Migrate基于model做upgrade的基本原理

      1)flask-migrate的官网:https://flask-migrate.readthedocs.io/en/latest/  2)获取帮助,在pycharm的控制台中输入 flask d ...

  4. Python学习笔记1——人人都爱列表

    一些BIF函数在列表中的应用: Python 3.3.4 (v3.3.4:7ff62415e426, Feb 10 2014, 18:13:51) [MSC v.1600 64 bit (AMD64) ...

  5. Java学习笔记--HashMap中使用object做key的问题【转】

    在HashMap中,如果需要使用多个属性组合作为key,可以将这几个属性组合成一个对象作为key.但是存在的问题是,要做get时,往往没办法保存当初put操作时的key object的referenc ...

  6. 学习笔记之08试用div做网页(滨院)-小作业

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  7. C#学习笔记(35)——事件做的登录案例

    说明(2018-4-9 20:11:42): 1. 先自定义了一个登录控件,可以输入账号.密码,点击登录.然后在Form1里面拖入这个控件,要求输入账号密码正确时,点击登录,控件显示绿色,否则显示红色 ...

  8. 自然语言处理NLP学习笔记三:使用Django做一个NLP的Web站点

    前言: 前面我们已经能初步实现一个中文自然处理语言的模型了,但交互界面是命令行的,不太友好. 如果想做一个类似http://xiaosi.trs.cn/demo/rs/demo的界面,那就还需要继续往 ...

  9. Mudo C++网络库第六章学习笔记

    muduo网络库简介 高级语言(Java, Python等)的Sockects库并没有对Sockects API提供更高层的封装, 直接用它编写程序很容易掉到陷阱中: 网络库的价值还在于能方便地处理并 ...

随机推荐

  1. 脱壳_00_压缩壳_ASPACK

    写在前面的话: Aspack是最常见的一种压缩壳,具有较好的兼容性.压缩率和稳定性,今天我们就来一起分析一下这个壳: 零.分析压缩壳: 0.在开始动态调试前,用PEID和LoadPE查看一些信息,做到 ...

  2. git 命令行下浏览器tig使用记录

    git 命令行下浏览器tig使用记录 tig 是一款优化 git 命令行的工具,使 git 命令行更加的便捷人性化 .如果用习惯了,会上瘾. 以下是一些使用记录: 安装成功后,在 Repo 文件夹下, ...

  3. 基于CNN网络的汉字图像字体识别及其原理

    现代办公要将纸质文档转换为电子文档的需求越来越多,目前针对这种应用场景的系统为OCR系统,也就是光学字符识别系统,例如对于古老出版物的数字化.但是目前OCR系统主要针对文字的识别上,对于出版物的版面以 ...

  4. 6、JVM--类文件结构(上)

    6.1.概述 写的程序需要经编译器翻译成由0和1构成的二进制格式才能由计算机执行 6.2.无关性基石 Java在刚刚诞生之时曾经提出过一个非常著名的宣传口号:“一次编写,到处运行(Write Once ...

  5. rebase合并commit步骤详解

    网上关于rebase合并commit有很多文章,但大部分中间一些步骤没有写明 第一步:在终端输入 git rebase -i [startPoint] [endPoint] 并回车 第二步:编辑指令, ...

  6. oracle查询2G以上的表

    SELECT a.*, b.comments  FROM (SELECT OWNER,               SEGMENT_NAME,               SEGMENT_TYPE,  ...

  7. lnmp服务器配置HTTPS

    server { server_name ktsf.weiyou18.com; #listen 80; listen 443; ssl on; ssl_certificate /usr/local/n ...

  8. Python2.7-shelve

    shelve模块,持久化对象数据,可以说是 pickle 模块的封装,用于把像字典一样的以键-值存储的数据持久化存储,像操作数据库.当我们写程序的时候如果不想用关系数据库那么重量级的东东去存储数据,不 ...

  9. HDU 2709 Sumsets 经典简单线性dp

    Sumsets Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Sub ...

  10. Features + Git + Drush,打造你的Drupal开发与维护标准工作流

    还在为如何将本地的开发工作如何部署到生产环境而皱眉头?本文以实战历程教你如何一步步将你的工作成果从开发环境部署到生产环境. 如题所示,需要用到Features, Git, Drush:如果你还不知道他 ...