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. linux通配符含义

    linux通配符含义: .    当前目录**** ..   当前目录的上一级目录**** *    通配符,代表任意0个或多个字符***** ?   通配符,代表重复0个或一个0前面的字符 :    ...

  2. windows注册表

    如何导入与导出注册表 进入注册表编辑器,选择“文件”“导出”命令,打开“导出注册表文件”对话框.选择保存位置并为其取名,单击保存即可完成注册表的备份. 打开注册表编辑器,选择“文件”“导入”命令,打开 ...

  3. Django商城项目笔记No.18商品部分-数据表创建

    数据库表设计 在电商中对于商品,有两个重要的概念:SPU和SKU SPU = Standard Product Unit (标准产品单位) SPU是商品信息聚合的最小单位,是一组可服用.易检索的标准化 ...

  4. PyQt5--ToolBar

    # -*- coding:utf-8 -*- ''' Created on Sep 14, 2018 @author: SaShuangYiBing ''' import sys from PyQt5 ...

  5. 原生JS简单的无缝自动轮播

    最近在不断的加强巩固js.在学习jq和vue之后发现很多东西其实都是不明所以,有些底层的东西自己不懂,到头来也只是一昧的使用,一直在用别人的东西,对自己的成长帮助也不大. 万丈高楼平地起,基础打扎实了 ...

  6. Spring-IOC XML 配置多个相同 ID 的 bean 加载分析

    我们现在仍以 xml 中配置 bean 的方式来 使用 Spring ,不考虑注解和扫包 配置相同id 的bean 定义一个 bean 类 TransactionManager /** * @auth ...

  7. Docker技术入门与实战 第二版-学习笔记-5-容器-命令及限制内存与cpu资源

    1.启动容器 启动容器有两种方式: 基于镜像新建一个容器并启动 将在终止状态(stopped)的容器重新启动 1)新建并启动——docker run 比如在启动ubuntu:14.04容器,并输出“H ...

  8. Lr场景设计-hc课堂笔记

    性能测试最基本也是最难的部分:场景设计.瓶颈分析和定位 10个业务10个脚本,每个脚本单独执行:单独场景.10个脚本一起执行:混合场景.10个业务1个脚本:可以设计不同用户登录,分别做不同的操作等场景 ...

  9. Posts Tagged ‘This system is not registered to Red Hat Subscription Management. You can use subscription-manager to register问题的解决办法

    HowTo Install redhat package with YUM command without RHN February 26, 2014 in Redhat / Linux Tips a ...

  10. HDU 1978 How many ways(经典记忆化搜索)

    S - How many ways Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u S ...