【Muduo源码剖析笔记】Muduo Base库结构简介
作为第一次阅读源码的新手,感觉Muduo库的结构和代码都还是相对其他源码清晰和简单的。Base库包含了实现网络库所需的基础组件,但是自己第一次读的时候,在各个头文件的依赖关系中绕来绕去走了一些弯路,因此笔记以源代码中,头文件和实现文件为一个编译模块为单位梳理一下Base库的结构组成。
Base库的组件有多种类型,有的组件自己实现了单一功能,比如noncopyable模块可以为其他组件提供不可复制的tag提示。有的多个组件结合在一起实现了一个功能,比如用于管理线程相关的组件。笔记尝试将组件分为以下几类:
全局函数变量组件:定义了一些在不同命名空间下的函数和变量,供其他所有的组件调用。有时候这些函数变量也会出现在其他模块中。
功能组件:特别指提供与网络库没有直接相关的功能模块,更多的是与提供与编程角度相关的功能。
结构组件:提供与网络库相关的功能模块,可供其他模块调用,是整个网络库的组成部分之一。
个人阅读源码学习顺序可以从功能组件到结构组件,从基础到比较上层的功能顺序阅读。
各个组件的详细功能笔记后续再整理发出,这里只对模块的功能进行简介。
全局函数组件
CurrentThread
其并未定义新的类,定义了在CurrentThread命名空间里的线程相关的全局函数。这些函数主要供子线程管理自己的线程相关数据信息。
Types
定义了类型转换的两个函数和一个将一片内存置零的函数。
ProcessInfo
封装了线程相关的一些函数,和读取系统文件的一些函数。
功能组件
noncopyable(copyable)
定义了noncopyable类,属于一个tag类,可以供其他任何class继承,表示类不可以调用拷贝构造函数和赋值构造函数,这两个函数都使用C++11的delete关键字删除掉了。
copyable同理。
Atomic.h
定义了模板类AtomicIntegerT,提供其他文件使用AtomicIntegerT<int32_t> AtomicInt32和:AtomicIntegerT<int64_t> AtomicInt64。该类内部包含一个类型为模板类T的value_数据成员,封装了与之相关的操作函数,比如获得该数,自加等操作。其使用了GCC内置的原子操作实现,因此是原子级别的。
StringPiece
定义了两个类,一个为StringArg,内部包含一个const char* str_数据成员,属于C风格表示的字符串,这个类常用于作为函数的参数,由于其定义了两个初始化函数,即可以使用const char*初始化,也可以用const string&初始化。
另一个StringPiece类,其也是表示一个const char*的字符串,内部包含一个const char *类型指针和int类型的length_数据成员,同时封装了与之相关的操作函数。其目的是为了节省string的拷贝开销。
// You can use StringPiece as a function or method parameter. A StringPiece
// parameter can receive a double-quoted string literal argument, a “const
// char*” argument, a string argument, or a StringPiece argument with no data
// copying. Systematic use of StringPiece for arguments reduces data
// copies and strlen() calls.
Exception
定义了Exception类,包含两个string类型的数据成员用于保存异常的相关信息。
Timestamp
顾名思义定义了时间戳的类。
TimeZone
封装了时间区相关的类(还没阅读,有点繁琐)
结构组件
同步原语
包含mutex、Condition和CountDownLatch。管理互斥锁,条件变量和基于互斥锁、条件变量实现的CountDownLatch。基于RAII的思想管理这些系统资源。
FileUtil
封装了一个名为AppendFile的类,包含一个文件描述符,来管理这个文件资源。
日志库
按照自下而上的顺序,包含Logstream、Logging、AsyncLogging、LogFile。整个流程是,LogStream封装了一块内存空间以及对此相关操作的函数。Logging定义了一个Logger类,其封装了对相关操作函数的调用逻辑,其被其他需要输出日志信息的子线程调用,把日志信息放在自己的buffer后,再把这个结果通过一个全局输出函数g_output输出到AsyncLogging类的Buffer中。AsyncLogging类位于主线程区,保存两个Buffer来缓冲日志数据。然后日志线程会运行AsyncLogging类中定义的线程函数,在日志线程中分配两个区来获取主线程中的日志数据,然后通过自己定义的一个局部变量LogFile,通过LogFile实现IO读取完成日志记录。
任务队列
BlockingQueue和BoundedBlockingQueue。实现阻塞式的队列获取,都是模板类,模板类型就是你想放进队列中的数据类型。比如线程池就会把任务(函数指针)放入队列中。Bounded的队列是有界的,BlockingQueue可以无限往里面塞。
线程相关
Thread中定义了Thread类,其通常由主线程创建,包含与线程相关的信息,比如线程的id,运行的函数指针地址等等,和与线程操作相关的函数比如让其开始执行。用于主线程管理子线程的创建与销毁。
ThreadLocal和ThreadLocalSingleton都能帮你获取一份各个子线程独有的一份线程特有数据,区别是否是单例而已。
ThreadPool实现了线程池的创建和管理,其中会使用到任务队列,让创建的线程都去争抢队列中的任务。