事件处理模式

AI生成,未完全消化……

一、Reactor 模式(反应器模式)

核心思想:基于 “事件驱动”,通过一个集中式的事件循环等待事件发生,再将事件分发给对应的处理器处理。其核心是 “等待事件→分发处理” 的同步触发机制。

1. 核心组件

  • 事件源(Event Source):产生事件的实体,如网络套接字(socket)、文件描述符(fd)等。

  • 事件多路分发器(Event Multiplexer):监听事件源,当事件就绪时通知反应器(如 Linux 的epollpoll,Windows 的select)。

  • 事件处理器(EventHandler):定义事件处理接口(如handleRead()handleWrite()),由具体业务逻辑实现。

  • 反应器(Reactor):协调事件多路分发器和事件处理器,负责注册 / 注销事件、分发就绪事件。

2. 工作流程

  1. 应用程序向 Reactor 注册事件(如 “读就绪”)及对应的处理器;

  2. Reactor 通过事件多路分发器阻塞等待事件就绪;

  3. 当事件就绪(如 socket 可读),事件多路分发器通知 Reactor;

  4. Reactor 根据事件类型调用对应处理器的处理方法(如handleRead());

  5. 处理器完成业务逻辑(如读取数据、解析协议)。

3. 关键特性

  • 同步 I/O 模型:I/O 操作(如read()/write())由应用程序主动发起,Reactor 仅负责 “通知事件就绪”,不参与实际 I/O。

  • 优势:实现简单,无操作系统异步 I/O 依赖,适合 I/O 密集型场景(如高并发网络服务器)。

  • 劣势:若处理器处理耗时任务(如复杂计算),会阻塞事件循环,导致其他事件延迟处理。

4. C++ 应用示例

  • 知名网络库muduo(陈硕实现)基于 Reactor 模式,用epoll作为事件多路分发器,配合线程池处理耗时任务。

  • 代码框架示意:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    // 事件处理器接口
    class EventHandler {
    public:
    virtual void handleRead() = 0;
    virtual void handleWrite() = 0;
    virtual int getFd() = 0; // 获取事件源fd
    };

    // Reactor核心
    class Reactor {
    public:
    void registerHandler(EventHandler* handler, int events); // 注册事件
    void removeHandler(EventHandler* handler); // 注销事件
    void loop() { // 事件循环
    while (true) {
    // 调用epoll_wait等待事件就绪
    int n = epoll_wait(epfd, events, MAX_EVENTS, -1);
    for (int i = 0; i < n; ++i) {
    EventHandler* handler = (EventHandler*)events[i].data.ptr;
    if (events[i].events & EPOLLIN) {
    handler->handleRead(); // 分发读事件
    }
    if (events[i].events & EPOLLOUT) {
    handler->handleWrite(); // 分发写事件
    }
    }
    }
    }
    };

二、Proactor 模式(前摄器模式)

核心思想:基于 “异步 I/O”,由操作系统完成实际 I/O 操作后,通知应用程序处理 I/O 结果。其核心是 “发起异步 I/O→等待完成→处理结果”。

1. 核心组件

  • 异步操作处理器(Async Operation Processor):由操作系统提供,负责执行异步 I/O(如读取数据到缓冲区)。

  • 完成事件队列(Completion Queue):存储 I/O 操作完成的结果(如数据、错误码)。

  • 完成事件多路分发器:监听完成事件队列,通知 Proactor 有 I/O 完成。

  • Proactor:协调异步操作和结果处理,将完成事件分发给处理器。

  • 完成处理器(Completion Handler):处理 I/O 完成后的业务逻辑(如解析数据)。

2. 工作流程

  1. 应用程序发起异步 I/O 请求(如aio_read),指定缓冲区、回调处理器,并注册到 Proactor;

  2. 操作系统的异步操作处理器执行 I/O(如从 socket 读取数据到缓冲区);

  3. I/O 完成后,操作系统将结果放入完成事件队列;

  4. Proactor 通过完成事件多路分发器检测到完成事件,调用对应完成处理器;

  5. 处理器处理 I/O 结果(如解析缓冲区数据)。

3. 关键特性

  • 异步 I/O 模型:I/O 操作由操作系统完成,应用程序仅处理结果,避免 I/O 阻塞。

  • 优势:适合高并发场景,I/O 效率高(无应用程序轮询或阻塞等待)。

  • 劣势:依赖操作系统异步 I/O 支持(如 Windows 的 IOCP、Linux 的io_uring),实现复杂,移植性差。

4. C++ 应用示例

  • Linux 下可基于io_uring实现 Proactor,Windows 可基于 IOCP。

  • 代码框架示意(简化io_uring用法):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    // 完成处理器
    class CompletionHandler {
    public:
    virtual void handleCompletion(ssize_t res) = 0; // 处理I/O结果
    };

    // Proactor核心
    class Proactor {
    public:
    // 发起异步读
    void asyncRead(int fd, void* buf, size_t len, CompletionHandler* handler) {
    // 提交io_uring异步读请求
    struct io_uring_sqe* sqe = io_uring_get_sqe(&ring);
    io_uring_prep_read(sqe, fd, buf, len, 0);
    sqe->user_data = (uint64_t)handler; // 绑定处理器
    io_uring_submit(&ring);
    }

    void loop() { // 事件循环
    while (true) {
    struct io_uring_cqe* cqe;
    io_uring_wait_cqe(&ring, &cqe); // 等待I/O完成
    CompletionHandler* handler = (CompletionHandler*)cqe->user_data;
    handler->handleCompletion(cqe->res); // 处理结果
    io_uring_cqe_seen(&ring, cqe);
    }
    }
    };

并发编程模式

一、半同步 / 半异步模式(Half-Sync/Half-Async)

核心思想:将系统分为 “异步层” 和 “同步层”,异步层处理 I/O 事件,同步层处理业务逻辑,通过队列连接两层,平衡效率与复杂度。

1. 三层结构

  • 异步层:采用 Reactor 模式处理 I/O 事件(如接收连接、读写数据),不阻塞,高效响应事件。

  • 同步层:由线程池组成,同步执行业务逻辑(如协议解析、事务处理),避免异步层被耗时任务阻塞。

  • 任务队列:异步层将待处理的任务(如 “解析请求”)放入队列,同步层线程从队列取任务执行。

2. 工作流程

  1. 异步层(Reactor)接收网络事件(如客户端请求),将请求封装为任务;

  2. 异步层将任务放入任务队列;

  3. 同步层的线程池从队列中取任务,同步执行业务逻辑(如数据库操作);

  4. 业务处理完成后,结果通过队列返回给异步层,由异步层发送响应。

3. 关键特性

  • 分离 I/O 与业务:异步层专注高效 I/O,同步层专注复杂业务,降低耦合。

  • 优势:兼顾高并发 I/O 和复杂业务处理,避免单一线程阻塞整个系统。

  • 劣势:任务队列可能成为瓶颈(需考虑线程安全和队列长度);线程池管理增加复杂度。

4. C++ 应用示例

  • 多数商业服务器框架采用此模式,如 Nginx(异步层处理连接,同步进程处理请求)。

  • 代码框架示意:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    // 异步层(Reactor)
    class AsyncLayer {
    public:
    void onRequest(Request* req) {
    taskQueue.push(req); // 请求放入队列
    cond.notify_one(); // 唤醒同步层线程
    }
    };

    // 同步层(线程池)
    class SyncLayer {
    public:
    SyncLayer() {
    for (int i = 0; i < 4; ++i) { // 4个工作线程
    threads.emplace_back([this]() {
    while (true) {
    std::unique_lock<std::mutex> lock(mtx);
    cond.wait(lock, []{ return !taskQueue.empty(); });
    Request* req = taskQueue.front();
    taskQueue.pop();
    lock.unlock();

    processRequest(req); // 同步处理业务
    }
    });
    }
    }
    };

二、领导 / 追随者模式(Leader/Follower)

核心思想:线程池中的线程轮流担任 “领导者”,领导者负责等待事件;事件到来后,领导者指定一个 “追随者” 成为新领导者,自己转为 “处理者” 处理事件;处理完成后回归追随者队列。

1. 核心组件

  • 线程池:包含多个相同角色的线程(领导者 / 追随者 / 处理者)。

  • 事件多路分发器:仅由当前领导者持有,用于等待事件。

  • 事件队列:暂存待处理事件(可选,用于批量处理)。

  • 线程屏障(Barrier):协调线程角色切换(如领导者选举)。

2. 工作流程

  1. 初始时,一个线程成为领导者,其他为追随者;

  2. 领导者通过事件多路分发器等待事件;

  3. 事件到来后,领导者从追随者中选一个线程作为新领导者(接管事件多路分发器);

  4. 原领导者转为处理者,处理当前事件;

  5. 处理完成后,处理者变回追随者,等待下次选举。

3. 关键特性

  • 无锁设计:线程角色切换通过屏障协调,避免锁竞争,减少开销。

  • 优势:适合短任务处理(如事件分发),线程切换效率高,适合高并发场景。

  • 劣势:不适合长任务(会阻塞领导者选举,导致事件处理延迟);实现复杂(需精细控制线程状态)。

4. C++ 应用示例

  • 常用于高性能事件驱动框架(如 ACE 库的ACE_Leader_Follower)。

  • 核心逻辑示意:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    class LeaderFollower {
    public:
    void run() {
    while (true) {
    if (isLeader()) {
    // 领导者等待事件
    Event* event = eventDemux.wait();
    // 选新领导者
    Thread* newLeader = selectFollower();
    newLeader->becomeLeader();
    // 处理事件
    processEvent(event);
    // 变回追随者
    becomeFollower();
    } else {
    // 追随者等待成为领导者
    barrier.wait();
    }
    }
    }
    };

总结与对比

模式 核心机制 适用场景 典型依赖 / 库
Reactor 同步事件驱动(等事件→处理) 高并发 I/O、短任务 epollmuduo
Proactor 异步 I/O(OS 完成 I/O→通知) 超大规模并发、异步 I/O 支持 IOCP、io_uring
半同步 / 半异步 异步 I/O + 同步业务 + 任务队列 复杂业务 + 高并发 I/O 线程池 + Reactor
领导 / 追随者 线程轮流领导 + 无锁处理 高并发短任务、事件分发 ACE 库、自定义线程池

在 C++ 网络编程中,Reactor 模式因实现简单且兼容性好,是最常用的基础模式;Proactor 适合对性能要求极高且依赖特定 OS 的场景;半同步 / 半异步是架构级设计,平衡了效率与业务复杂度;领导 / 追随者则适合追求极致性能的短任务处理场景