Linux-C++开发项目:基于Reactor模式的高性能并发服务器(Ubuntu实现)———学习笔记(续集)

第一集:http://t.csdnimg.cn/ZvTAR

第二集:http://t.csdnimg.cn/yHPuj

3.1.8LoopThread模块

前面提到过本项目的目标是实现一个One Thread One Loop,那么LoopThread模块就是负责创建线程和对应的EventLoop。

其中one loop one thread 网络模型,也称为 Reactor 模型。loop指事件循环,将文件描述符可读称为一个可读事件,将文件描述符可写称为一个可写事件,在TCP网络编程中,我们重点关注socket文件描述符上的读写事件。事件循环是指监控文件描述符上的读写事件,当有文件描述符变得可读或可写时,理解为发生了一次事件循环,即检测到一次事件发生。

LoopThread.hpp

#ifndef LOOPTHREAD_HPP
#define LOOPTHREAD_HPP

#include <thread>
#include <mutex>
#include <condition_variable>
#include "EventLoop.hpp" // 假设 EventLoop 类的声明在这个头文件中

class LoopThread
{
public:
    LoopThread();
    EventLoop* GetLoop();

private:
    void ThreadEntry();

    std::mutex _mutex;
    std::condition_variable _cond;
    EventLoop* _loop; // 这个对象需要在线程内实例化
    std::thread _thread;
};

#endif // LOOPTHREAD_HPP

LoopThread.cpp

#include "LoopThread.hpp"

LoopThread::LoopThread()
    : _loop(nullptr), _thread(&LoopThread::ThreadEntry, this)
{
}

EventLoop* LoopThread::GetLoop()
{
    EventLoop* loop = nullptr;
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _cond.wait(lock, [&]() { return _loop != nullptr; }); // 如果 _loop 为空就一直阻塞
        loop = _loop;
    }
    return loop;
}

void LoopThread::ThreadEntry()
{
    EventLoop loop;
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _loop = &loop;
        _cond.notify_all(); // 确实创建了一个 EventLoop 对象,GetLoop() 才能返回
    }
    loop.Start(); // 线程内启动 loop,loop 对象不会被销毁
}

3.1.9LoopThreaddPool模块

LoopThreadPool模块的本质是一个线程池。它的作用就是对LoopThread做管理。

线程池:在应用程序启动时创建一定数量的线程,并将它们保存在线程池中。当需要执行任务时,从线程池中获取一个空闲的线程,将任务分配给该线程执行。当任务执行完毕后,线程将返回到线程池,可以被其他任务复用。

LoopThreadPool.hpp

#ifndef LOOPTHREADPOOL_HPP
#define LOOPTHREADPOOL_HPP

#include <vector>
#include "LoopThread.hpp" // 假设 LoopThread 类的声明在这个头文件中
#include "EventLoop.hpp"
class EventLoop;
class LoopThreadPool
{
public:
    LoopThreadPool(EventLoop *baseloop);

    void SetThreadCount(int count); // 设置线程数量
    void Create(); // 启动线程池
    EventLoop *NextLoop(); // 任务的分发要平均分配给每个线程,这里使用循环轮转的方式分配

private:
    int _thread_count; // 线程数量
    int _next_index; // 下标
    EventLoop *_baseloop; // 主线程EventLoop
    std::vector<LoopThread *> _threads;
    std::vector<EventLoop *> _loops;
};

#endif // LOOPTHREADPOOL_HPP

LoopThreadPool.cpp

#include "LoopThreadPool.hpp"

LoopThreadPool::LoopThreadPool(EventLoop *baseloop)
    : _thread_count(0), _next_index(0), _baseloop(baseloop)
{}

void LoopThreadPool::SetThreadCount(int count)// 设置线程数量
{
    _thread_count = count;
}

void LoopThreadPool::Create()// 启动线程池
{
    if (_thread_count > 0)
    {
        _threads.resize(_thread_count);
        _loops.resize(_thread_count);
        for (int i = 0; i < _thread_count; i++)
        {
            _threads[i] = new LoopThread(); // LoopThread一旦创建就开始工作
            _loops[i] = _threads[i]->GetLoop();
        }
    }
}

EventLoop *LoopThreadPool::NextLoop()// 任务的分发要平均分配给每个线程,这里使用循环轮转的方式分配
{
    if (_thread_count == 0)
        return _baseloop; // 如果线程数量为0,就返回主线程的EventLoop
    _next_index = (_next_index + 1) % _thread_count;
    return _loops[_next_index];
}

3.1.10主从Reactor模式

基本概念:

Reactor:负责多路分离I/O事件(如socket可读、可写事件)的处理器。Reactor将这些事件分发给相应的事件处理器(Handler)。

Handler:事件处理器,负责具体I/O事件的处理,如读写网络数据、处理业务逻辑等。

主Reactor监听连接

        主Reactor在主线程中运行,监听网络端口等待新连接请求。

        当有新的连接请求到达时,主Reactor接受连接并将该连接分发给某个从Reactor。

从Reactor处理I/O事件

        从Reactor可以有多个,每个从Reactor通常由一个线程或一组线程来处理。

        从Reactor接收到主Reactor分发的连接后,负责处理该连接上的I/O事件,如读写网络数据、处理业务逻辑等。

        从Reactor在处理I/O事件时,使用多路复用技术(如epoll、kqueue)来监听多个连接的I/O事件。

        首先可以明确一个点,当服务器没有创建任何线程的时候,这个服务器只有一个主线程。如果为服务器创建多个线程的时候,该服务器就是一个多线程程序。
那么一个线程对应一个Reactor,那么就可以规定每个Reactor的处理任务。在本项目当中,主线程负责连接的建立,即,主线程的Reactor负责连接套接字的创建和销毁;其他的从线程,即从线程的Reactor负责连接的业务处理。

主从Reactor模式的逻辑关系图如下所示:

整合测试2 

test2.cpp

#include <iostream>
#include <functional>
#include <cstring>
#include "server.hpp"  // Assuming these are the header files for Socket, Channel, Buffer, and EventLoop
#include "Channel.hpp"
#include "EventLoop.hpp"
#include "TimerTask.hpp"
#include "TimerWheel.hpp"
#include "Socket.hpp"
#include "Buffer.hpp"
#include "LoopThreadPool.hpp"

EventLoop loop;

void WriteHandle(Socket *sock, Channel *ch, Buffer *buf) {
    // Send the data from the buffer to the socket
    sock->Send(buf->ReadPosition(), buf->ReadAbleSize());

    // Disable write events and enable read events for the channel
    ch->DisableWrite();
    ch->EnableRead();
}

void ReadHandle(Socket *sock, Channel *ch) {
    char buffer[1024] = {0};  // Buffer to store received data
    ssize_t n = sock->Recv(buffer, sizeof(buffer) - 1);  // Receive data from t
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值