Reactor反应堆模式

Reactor是事件分发器,基于IO 多路复用(epoll/poll/select) + 事件回调,把IO事件、读写、异常统一监听、分发到对应处理函数,是高性能网络服务经典模型

总结来说,Reactor = IO 多路复用 + 事件分发 + 回调

1. 思路

2. 参考代码

Reactor模式实现代码

3. 附加

OneThreadOneLoop多进程方案

One Thread One Loop (OTOL)是一种设计模式,通常用于描述基于事件驱动编程(Event Driven Programming)的架构,特别是在使用异步I/O(Asynchronous I/O)框架时。这种模式强调每个线程运行一个独立的事件循环(Event Loop),从而实现高效的并发处理。

核心概念

事件循环(Event Loop):

  • 事件循环是异步编程的核心,负责监听事件(如 I/O 操作、定时器事件等)并触发相应的回调函数
  • 通常是一个单线程的执行模型,通过多路复用技术(如 epoll 、 select 或 poll )高效地管理多个 I/O 操作

单线程模型

  • 在 One Thread One Loop 模式中,每个线程运行一个独立的事件循环
  • 这种设计避免了多线程编程中的复杂同步问题,同时利用了现代操作系统高效的 I/O 多路复用机制
  • 只要把单 Reactor 写完,扩展多进程很容易
  • 每个进程管理的连接和 fd,彼此不要重复
  • 每个 Reactor,自己处理自己的 sockfd 的完整生命周期,不涉及任何 IO 穿插、乱序问题

多线程方案1

Eventfd事件驱动

如果不使用管道的话,可以使用Eventfd

  • 是一个轻量级的事件通知机制,基于文件描述符
  • 它可以与I/O多路复用机制(如epoll )结合使用
  • 内核维护一个64位的计数器, write会增加计数器, read 会减少

进程间事件通知:

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/eventfd.h>
#include <sys/wait.h>

int main() {
    // 创建一个 eventfd 文件描述符,用来发事件
    // EFD_CLOEXEC:执行新程序时自动关闭,安全规范
    int efd = eventfd(0, EFD_CLOEXEC);
    if (efd == -1) {
        perror("eventfd");
        return 1;
    }

    // fork() 创建子进程
    // 调用后,变成两个进程:父进程 + 子进程
    pid_t pid = fork();
    if (pid == -1) {
        perror("fork");
        return 1;
    }

    if (pid == 0) {
        // 这里是 【子进程】
        uint64_t value;
        // 阻塞等待:读取 eventfd,直到有人写入才会继续
        read(efd, &value, sizeof(value));
        printf("Child process received event\n");
        close(efd);
        return 0;
    } else {
        // 这里是 【父进程】
        uint64_t value = 1;
        // 向 eventfd 写入 = 发送事件
        write(efd, &value, sizeof(value));
        printf("Parent process sent event\n");
        
        wait(NULL); // 等待子进程结束
        close(efd);
        return 0;
    }
}

流程:

创建 eventfd --> fork子进程 --> 子进程阻塞在 read,等事件 --> 父进程 write,发送事件 --> 子进程收到,打印提示 --> 结束

线程间事件通知:

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/eventfd.h>
#include <pthread.h>

// 工作线程函数
void* worker_thread(void* arg) {
    int efd = *(int*)arg; // 获取 eventfd
    uint64_t value;
    
    // 阻塞等待事件
    read(efd, &value, sizeof(value));
    printf("Worker thread received event\n");
    return NULL;
}

int main() {
    // 创建 eventfd
    int efd = eventfd(0, EFD_CLOEXEC);
    if (efd == -1) {
        perror("eventfd");
        return 1;
    }

    pthread_t thread;
    // 创建工作线程
    pthread_create(&thread, NULL, worker_thread, &efd);

    // 主线程:发送事件
    uint64_t value = 1;
    write(efd, &value, sizeof(value));
    printf("Main thread sent event\n");

    // 等待工作线程结束
    pthread_join(thread, NULL);
    close(efd);
    return 0;
}

流程:

创建 eventfd --> 创建一个工作线程 --> 工作线程阻塞在 read,等事件 --> 主线程 write,发送 --> 工作线程收到,打印提示 --> 结束

Eventfd工作模式

  1. 普通模式:不设置 EFD_SEMAPHORE ,读取的时候,计数器会清空
  2. 设置EFD_SEMAPHORE :信号量模式

多线程方案2

相关推荐
星恒讯工业路由器31 分钟前
AGV集群通信架构:从单点到百台级调度的挑战与对策
网络·物联网·信息与通信·工业物联网·通信架构·agv集群·实时调度
夜月yeyue2 小时前
AUTOSAR CP 从上电到 Runnable
c语言·网络·tcp/ip·车载系统
lsh曙光2 小时前
延时at指令和定时cron指令
linux·服务器·网络
treesforest2 小时前
IP定位技术在网络犯罪侦查中的应用与价值
网络·网络协议·tcp/ip·网络安全·ip归属地查询·反欺诈
圆山猫2 小时前
[Virtualization](四):Linux KVM/RISC-V 的 vCPU 运行路径
java·linux·risc-v
XR1234567883 小时前
企业全光网络架构选型技术白皮书:从物理层到运维层的全链路分析
运维·网络·架构
似的8353 小时前
一步一步学习使用FireMonkey动画() 使用TAnimator类创建动画
linux·学习·nginx
萧瑟余晖4 小时前
Java深入解析篇九之NIO详解
java·网络·nio
我不管我就要叫小猪4 小时前
嵌入式Linux----网络通信
linux·运维·服务器
小王C语言4 小时前
【7. 实现登录注册模块】:实现会话管理、注册/登录/退出 API
网络·c++