day08-CurrentThread
获取系统级线程ID,第一次获取后就存起来,不再调用系统函数 1234567891011121314151617181920212223#pragma once#include <sys/syscall.h>#include <unistd.h>class EventLoop;namespace CurrentThread{ inline thread_local int t_cachedTid = 0; //每个线程有自己专属的 ID 缓存。 //每个线程独有的 EventLoop* inline thread_local EventLoop* t_loopInThisThread = nullptr; inline int tid() { if(t_cachedTid == 0) { t_cachedTid = static_cast<pid_t>(::syscall(SYS_gettid)); } ...
day07-EpollPoller
EpollPoller是对 Linux epoll 的 C++ 封装,它负责:监听 fd → 等待事件 → 返回有事件的 Channel,它继承自 Poller(抽象类) EpollPoller.h123456789#pragma once #include <vector>#include <sys/epoll.h>#include "Poller.h"#include "Timestamp.h"class Channel; 1class EpollPoller : public Poller 继承Poller 成员变量1234567private: static const int kInitEventListSize = 16; using EventList = std::vector<epoll_event>; int epollfd_; EventList events_; kInitEventListSizeepoll 事件数组(events_)的初始容量...
day06-Poller
Poller 是对 Linux IO 多路复用(epoll)的封装抽象类。1 个 Poller 管理 多个 Channel,事件来了由 Poller 通知 Channel 处理,Poller = 监工,负责监听所有 fd 的事件(底层是 epoll) poller 是抽象基类,不能实例化,定义统一接口:poll、update、remove,子类 EPollPoller 真正实现 epoll 操作。 Poller.h12345678910#pragma once#include "noncopyable.h"#include "Timestamp.h"#include <vector>#include <unordered_map>class EventLoop;class Channel; 12345class Poller : noncopyable{private: EventLoop* ownerLoop_;}; 该Poller属于哪个EventLoop。 123pr...
day05-CMake编译
CMakelists.txt123456789101112cmake_minimum_required(VERSION 3.5)project(lpzmuduo)# mymuduo最终编译成so动态库,设置动态库的路径,放在根目录的lib文件夹下面set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)# 设置调试信息 以及 启动C++11语言标准set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -std=c++11 -fPIC")# 把当前目录下所有 .cpp 源文件,自动全部搜集起来,放进 SRC_LIST 里。aux_source_directory(. SRC_LIST)# 把所有搜到的 .cpp 一起编译成动态库add_library(lpzmuduo SHARED ${SRC_LIST}) 编译CMakelists.txt1234mkdir buildcd buildcmake ..make 创建bui...
day04-Channel
Channel是干什么的?Channel 是对 Linux epoll 模型的 C++ 面向对象封装。 它把: 文件描述符 (fd) fd 感兴趣的事件 (events) 事件发生后的回调函数 (callback) 实际发生的事件 (revents) 这四样东西封装成一个类,交给 EventLoop 统一管理。 Channel只做事件分发,不做任何 I/O 操作、不处理业务逻辑,真正读数据、处理连接、处理业务的是:TcpConnection而 Channel 只负责 通知 TcpConnection。 它的工作只有三件事: 向 epoll 注册 / 修改 / 删除 fd 的监听事件 保存用户设置的回调函数 epoll 检测到事件后,调用对应的回调函数 Channel和别的模块的关联Channel 就是 TcpConnection 和 EventLoop 之间的桥梁: TcpConnection 给 Channel 注册回调 Channel 给 EventLoop 提供 fd 和事件 EventLoop 让 Poller 监听 事件来了,Ch...
day03-InetAddress
InetAddress是C++ 封装 socket 网络地址的核心类,用于统一管理 sockaddr_in 结构体(IPv4 地址 + 端口),屏蔽底层系统调用细节。 InetAddress.h1234567891011121314151617181920212223#pragma once#include <string>#include <arpa/inet.h>#include <netinet/in.h>//封装socket地址class InetAddress{public: explicit InetAddress(uint16_t port = 0, std::string ip = "0.0.0.0"); explicit InetAddress(const sockaddr_in& addr) : addr_(addr) {} std::string toIp() const; std::string toIpPort() const; u...
day02-Logger
这个日志库的重构并没有完全参考muduo里的日志库,只是基于muduo里日志库的一些特点实现的一个简易日志库。 该日志库适配muduo的特点 异步模型,避免日志写入阻塞业务线程; 全局单例,整个程序只有一个日志实例,避免多实例文件写入冲突 内部用线程安全的阻塞队列缓存日志,保证多线程生产日志的线程安全 noncopyable.h1234567891011#pragma onceclass noncopyable{public: noncopyable(const noncopyable&) = delete; noncopyable& operator=(const noncopyable&) = delete;protected: noncopyable() = default; ~noncopyable() = default;}; 禁止类的拷贝 / 赋值,保证单例唯一性。 AssistFunc.h1234567template<typename T>std::string to_s...
day01-Timestamp
muduo网络库里实现了自己的日志系统 为什么网络程序要有日志?后台的网络服务没有UI界面,出现如:连接断开,请求超时等问题时需要靠日志进行定位,再查找原因 为什么muduo要自己实现一套日志库? muduo是单线程Reactor模型的高性能网络库,日志不能阻塞IO. muduo设计是轻量化,要避免第三方库依赖,所以要避免引入第三方日志库 Timestamp为什么要设计时间戳? 每一条日志都需要携带时间,否则将失去排查的意义。 因为需要精准记录在极短时间多个事件(连接建立、消息收发、超时触发)发生的先后顺序,普通秒级时间戳无法满足,需自己设计微秒级时间戳。 统一不同模块(日志,网络IO)的时间接口。 Timestamp.h12345#pragma once#include <string>#include <cstdint> // 明确int64_t类型#include <chrono> // 现代C++时间库 #pragma once 是防止头文件被重复包含 123456789101112131415class Timestamp...
3.工厂模式
工厂模式是创建型设计模式的核心代表,核心思想是将 “对象的创建逻辑” 与 “对象的使用逻辑” 分离,让调用者无需关心对象的具体创建细节,仅通过统一接口获取实例。它是大型项目(如 muduo 网络库)中解耦代码、提升扩展性的关键手段。 一、工厂模式的核心解决的问题在未使用工厂模式时,调用者需要直接new具体类,会导致: 强耦合:调用者依赖具体类(如EPollPoller),修改具体类需改动所有调用处; 创建逻辑分散:对象的创建条件(如 “系统是否支持 epoll”)散落在代码各处; 扩展性差:新增子类时,需修改所有new的地方。 工厂模式通过 “工厂” 统一管理创建逻辑,彻底解决以上问题。 二、工厂模式的三大分类根据复杂度和场景,工厂模式分为简单工厂、工厂方法、抽象工厂三类,适用场景逐步递进。 1. 简单工厂模式(Simple Factory)这是最基础的工厂模式,通过一个工厂类 / 静态方法,根据条件创建不同子类实例。 核心结构 抽象产品:定义产品的统一接口(如Poller); 具体产品:实现抽象产品的子类(如EPollPoller、PollPoller); 工厂:...
2.C++单例模式懒汉式推荐的两种实例化方法
方案 1:局部静态变量版(C++11+ 最优,推荐首选)代码实例:123456// 核心:懒汉式实例化 + 线程安全(C++11 标准保证) static LogicSystem& GetInstance() { // C++11 标准:局部静态变量的初始化是线程安全的,仅第一次调用时创建 static LogicSystem instance; return instance; } 核心原理: C++11 标准兜底:ISO C++11 明确规定,函数内的局部静态变量在多线程环境下,初始化过程会由编译器自动插入「原子操作 + 锁」,保证仅一个线程完成初始化,后续线程直接返回已初始化的实例; 懒加载:instance 直到第一次调用 GetInstance() 才会创建,程序启动时无开销; 自动析构:静态变量存储在进程的静态区,程序退出时会自动调用析构函数(无需手动释放,无内存泄漏)。 方案 2:用std::once_flag + std::call_once实现代码实例:可结合Lambda表达式...