muduo库学习笔记(-)

muduo库学习笔记

前言

code

注:个人水平有限,不能保证此文完全正确,如果错误,请不吝指出。

此文在观看《大并发服务器开发》视频时所做。

因此本文所讲基于muduo库0.9.1-beta版本,需要依赖cmake及boost.

sudo apt-get install cmake libboost-dev libboost-test-dev .

更新时间:<2018-03-12>

原创时间: <2018-03-12>

epoll/poll/select

面向对象编程与基于对象编程

  1. std::boost::function

  2. std::bootst::bind

muduo::base中类关系及作用

  1. copyable.h 一个空类,用来标识子类是值语义。

  2. Types.h 提供字符串类的声明,及两个类型转换函数模板。

    1. implicit_cast (隐式转换),使代码阅读时更明晰。
    2. down_cast (向下转型),基类指针转换为派生类指针,前提是基类指针指向派生类对象。
  3. Timestamp.h/cc 提供封装好的时间类。

    • 继承copyable,值语义。
    • 继承boot::less_than_comparable\,less_than_comparable:要求提供<,可自动实现>,<=,>=
    • BOOST_STATIC_ASSERT(sizeof(Timestamp) == sizeof(int64_t)); 编译期间的assert,在编译时就可以报错。
    • 打印64位整数使用 PRld64, printf(“%” PRld64 “\n”, value_64); 可以做到跨平台(32和64位)。
  4. Atomic.h 提供原子操作模板类。延伸阅读:无锁队列的实现

    1. 提供了AtomicInt32(用来标识线程数使用)和AtomicInt64(目前还未看出作用) 两个类。
    2. volatile关键字:确保本条指令不会因编译器的优化而省略,且要求每次直接读值。当要求使用volatile声明的变量的值时,系统总是重新从它所在的内存读取数据,而不是使用保存在寄存器中的备份。
  5. Exception.h/cc 提供异常类

    1. backtrace 栈回溯,保存各个栈帧的地址。
    2. backtrace——symbols,根据地址,转成相应的函数符号。
    3. c++会在编译时会对函数做名字改编(name mangling)。
    4. abi::__cxa_demangle 对c++的程序做名字还原。
  6. Thread.h/cc 线程类

    • Linux中进程与线程

      • Linux中每个程有一个pid,类型是pid_t,由getpid()取得。
      • Linux下每个POSIX**线**程也有一个id,类型是pthread_t,由pthread_self()取得
      • POSIX**线程id由线程库维护,其id空间是各个程独立的。(即不同的程中的线**程可能有相同的id)。
      • Linux中的POSIX线程库实现的线程其实也是一个程(LWP),只是该进程与主进程(启动线程的进程)共享一些资源而已,比如代码段,数据段等。
      • 有时候我们可能需要知道线程的真实pid。比如进程P1要向进程P2中的某个线程发送信号时,既不能使用P2的pid,更不能使用线程的pthread_id,而只能使用该线程的真实pid,称为tid。
      • 有一个函数gettid()可以得到tid,但glibc并没有实现该函数,只能通过 Linux的系统调用syscall来获取。
      • return syscall(SYS_gettid)

        1. 普通成员函数,隐含的第一个参数是 Thread*(this),调用是时候遵循 thiscall约定,某一个寄存器会保护this指针,不能直接作为pthread_create的入口函数。需要定义一个static的静态成员函数,传递this指针来调用。
        2. static AtomicInt32 numCreated_; //用来记录创建的线程数,原子操作类型,在Thread类的构造中加1,析构上减1.
        3. __thread 关键字可以定义每个线程各个的变量。只能用来修饰基本类型(内置类型(与C兼容的原始类型)或无构造函数的类(结构体)),POD类型。
        4. 将真实线程tid缓存起来,可以减少系统调用次数。
        5. namespace detail 内部使用的命名空间,对外不可见
        6. boost::is_same 用来判定两种类型是否是同一种类型
        7. pthread_atfork (void (*prepare)(void), void(*parent)(void), void(*child)(void));
      • 调用fork时,内部创建子进程前在父进程中调用prepare
      • 内部创建子进程成功后,父进程会调用parent
      • 子进程会调用child
      • fork 可能是在主线程中调用,也可能是在子线程中调用
      • fork得到一个新进程,新进程只有一个执行序列,只有一个线程(调用fork的线程被继承下来)
      • 实际上,对于编写多线程程序来说,我们最好不要再调用fork
      • 不要编写多进程多线程程序,要么用多进程要么用多线程
  7. Mutex.h 提供锁

    1. MutexLocal类
      1. 继承自boot::noncopyable,不可拷贝的,对象语义
    2. MutexLockGuard类(更常用)
      1. 使用RAII技法(通过生存期来管理资源,在构造函数中申请资源,在析构函数中释放资源)封装的MutexLocal类
  8. Condition.h/cc 条件变量类(Condition类)

    Created with Raphaël 2.1.2 Thread1 Thread1 mutex mutex Thread2 Thread2 锁住 mutex wait(等待条件成立) 锁住 mutex 更改条件(signal or broadcast) wait(条件成立) 解锁 解锁

    需要理解其中的wait函数,其实做了三件事

    1. 释放当前解锁mutex
    2. 判断条件是否成立,如不成立,则阻塞当前线程
    3. 条件成立,加锁mutex
  9. CountDownLatch.h/cc 倒计时门闩类

    • 可以用于所有子线程等待主线程发起“起跑”
    • 可以用于主线程等待子线程初始化完毕才开始工作
    • mutbale关键字,使const函数可以修改mutable数据成员的状态。
  10. BlockingQueue.h/BoundedBlockQueue.h 无界/有界缓冲区模板类(BlockingQueue/BoundedBlockQueue 模板类) (实际为生产者->消费者模型)

    Created with Raphaël 2.1.2 用有界队列来讲解生产者与消费者模型 生产者1 生产者1 生产者2 生产者2 队列 队列 消费者1 消费者1 消费者2 消费者2 队列是否已满? 使用的是 wait(条件变量) 利用第8条 Condition类。 列队未满 加锁 生产产品到队列中 解锁 队列非空 队列非空 生产者工作流程已说明完毕 下面说明消费者工作流程 队列是否非空 列队非空 加锁 消费队列中的产品 解锁 队列未满 队列未满 基本流程已说明完毕 下面随便写一些状态 队列是否已满? 队列未满 加锁 生产产品到队列中 解锁 队列是否已满? 队列已满 队列非空 队列非空 队列是否已满? 队列已满
    1. BoundedBlockingQueue中使用了 boost::circular_buffer(环形缓冲区)
      • 可以使用数组与求模运算自己实现环形缓冲区(boost中并不是这样实现的)
  11. ThreadPoll.h/cc 线程池类(ThreadPool类)(本质上也是生产者->消费者模型)

    graph TB
        subgraph ThreadPoll 
            Consumer["线程队列(消费者)"]-- "完成任务" -->任务队列
        end
        subgraph ExternalThreadPool
            Producer["外部线程(生产者)"]-- "提出任务" -->任务队列
        end

    1. muduo库中实现的是固定的线程池(即线程池中线程个数固定的),不需要考虑线程池中线程个数的动态伸缩。
    2. typedef boost::function\

cmake的使用

  1. muduo库中使用到的编译选项
    • -Wall //大部分警告
    • -Wextra // 一些额外的警告
    • -Werror //当出现警告时转为错误,停止编译
    • -Wconversion //一些要能改变值的陷式转换,给出警告
    • -Wno-unused-parameter //函数中出现未使用的参数,不给出警告
    • -Wold-style-case //C风格的转换,给出警告
    • -Woverloaded-virtual //如果函数的声明隐藏住了基类的虚函数,就给警告
    • -Wpointer-arith //对函数指针或者void*类型的指针进行算术操作时给出警告
    • -Wshadow //当一个局部变量遮盖住了另一个局部变量,或者全局变量时,给出警告
    • -Wwrite-strings //替换字符串常量的类型时const char[length],因此,把这样的地址复制给non-const char* 指针将产生警告。这些警告能够帮助你在编译期间发现企图写入字符串常量的代码
    • -march=native //指定cpu体系结构为本地平台

muduo库中还不理解的内容

  1. 无锁队列的实现
  2. O_CLOEXEC 的详细解释与具体作用
  3. boost自动测试框架

你可能感兴趣的:(muduo库学习笔记(-))