【仿muduo库实现并发服务器】LoopThreadPool模块

仿muduo库实现并发服务器

  • 1.LoopThread模块
    • 1.1成员变量
    • 1.2构造函数
    • 13线程入口函数
    • 1.4获取eventloop对象GetLoop()
  • 2.LoopThreadPool模块
    • 2.1成员变量
    • 2.2构造函数
    • 2.3配置线程数量
    • 2.4按照配置数量创建线程
    • 2.5依次分配Eventloop对象

1.LoopThread模块

这个模块是为了将EventLoop与线程整合起来。一个EventLoop对应一个线程。
要知道EventLoop对象实例化时就会将它的thread_id绑定,然后后续的RuninLoop操作里面就会判断当前执行流的线程id与eventloop对应的线程id进行比较,如果相同就说明是同一个线程,如果不相同,就说明不是同一个线程执行。

这里要注意的是:
eventloop对象的实例化必须在线程创建之后,也就是在线程的入口函数中进行创建,然后eventloop对象一创建出来就绑定该线程。

就是构造一个新的模块,它在里边既有线程又有eventloop,而且它是先有线程然后在线程里边再去实例化eventlop,这样就能够保证eventloop在出现的第一时刻就跟我们的一个线程是绑定到一起的。

【获取eventloop对象】
这个模块,它将线程跟eventloop给整合到一起了,那么问题就来了,那当我们外界说一个新连接到来了,现在要给它分配一个eventloop对象,怎么给它分配呢?我总得能够获取到这个evetloop对象吧,所以在这个里边我们需要提供一个接口叫做GetLoop,获取到eventloop对象的指针。
那么当外界可以获取到这个eventloop对象指针之后,当新连接到来时,就可以将该线程的eventloop分配给该线程,该连接它就绑定在该eventloop对应的线程上工作。
比如在执行各种操作的时候,进行事件监控的时候,它就会绑定到我们eventloop对应的线程里边去,要进行某些操作的时候也是把任务压入到我们对eventloop,它的任务队列里边。

【获取evnetloop同步问题】
要避免当我们的线程刚创建起来之后,还没来得及实例化创建eventloop该对象的时候,这时候外界如果要获取该线程的eventloop,调用Getloop操作时,获取到的就为空。所以这里存在一个同步问题,也就是从属线程要先实例化eventloop对象,主线程才能够获取eventloop对象。
所以这里面需要两个东西:锁与条件变量。

这2个东西,它的一个功能就是用于那么实现我们的一个loop操作的一个同步关系。因为呢?我们要避免那么线程创建之后,但是我们的eventloop,还没有被实例化之前就去获取loop的操作,这样的获取是会出问题,就是一个空了对不对所以要给它同步管理起来,也就是说你获取loop的时候,必须是它loop已经那么实例化完了才可以之间的,你如果没有实例化完那就不让你获取。

也就是在获取eventloop对象指针时,设置一个条件:eventloop对象指针不为空。
如果这个时候不满足,则主线程就去条件变量下阻塞等待,如果满足条件就会被唤醒,去获取eventloop对象指针。
而在线程的入口函数里面,在刚创建实例化eventloop对象之后,就立即发送通知,唤醒主线程。

1.1成员变量

private:std::thread _thread; // 用来创建线程,eventloop绑定的线程EventLoop *_loop;    // Eventloop的指针变量,这里不能实例化,必须在创建线程里面实例化eventloop// 下面两个用来保证loop的同步性,必须先实例化完loop,才能获取loopstd::mutex _mutex;             // 锁,用来保护loop资源std::condition_variable _cond; // 条件变量

1.2构造函数

在构造中,就使用C++中的线程库,创建线程。
所以该模块对象一旦创建出来,就代表创建了一个线程以及对应的eventloop对象。

public:LoopThread() : _loop(NULL), _thread(std::bind(&LoopThread::ThreadEntry, this)){}

13线程入口函数

该线程一旦创建出来,就要执行的任务就是:
1.创建eventloop对象
2.唤醒主线程
3.启动eventloop
(eventloop一旦启动它就会循环监控在它上面的描述符的各种事件是否就绪,一旦就绪就会获取就绪的事件以及描述符,执行对应的回调函数,并且执行任务队列中的任务)

private:// 线程的入口函数void ThreadEntry(){// 首先创建对应的Eventloop对象EventLoop loop;_loop = &loop;// 创建完就唤醒可能阻塞的主线程_cond.notify_all();// 该线程就开始启动工作:_loop->Start();// 1.进行事件监控,并获取就绪的事件和fd 2.进行就绪事件处理3.执行任务队列里的任务}

1.4获取eventloop对象GetLoop()

 // 获取该线程对应的loop是由主线执行的,所以存在线程安全问题,并且还要保证loop的同步问题EventLoop *GetLoop(){EventLoop *loop = NULL; // 为了保证临界资源_loop的安全性,在访问时最后将临界资源拷贝过去,最后返回的时候就不涉及临界资源的访问{std::unique_lock<std::mutex> _lock(_mutex); // 加锁// 确保获取_loop之前已经被实例化_cond.wait(_lock, [&](){ return _loop != NULL; }); // 如果这时_loop为空,则主线程就一直阻塞在条件变量的队列中loop = _loop;}return loop;}

实现了我们的一个主从react模型,主线程只负责对监听套件字的处理,获取新连接
保证我们连接的一个获取效率不会因为我们的一个业务的处理而导致无法去获取连接
而我们的从属react呢?当它获取到新连接之后,将我们的新连接分配给我们的从属react线程中,让从属线程对它进行一个事件监控,进行事件监控然后事件的处理以及业务的处理。

2.LoopThreadPool模块

LoopThreadPool线程池是对所有的LoopThread线程进行管理及分配。
主要提供的功能是:
1.能够让用户设置创建几个线程。

不过要注意当用户设置的从线程数据为0时,这时候新连接的事件监控就必须要有主线程中的baseloop进行监控管理。所以该线程池中必须要传入主线程的baseloop对象,以防止从属线程的数量为0。

在主从Reactor模型中,主线程只负责获取新连接,而从属线程负责对连接进行监控和处理,当线程池中线程的个数为0时,就变成了单Reactor服务器,主线程既负责或者新连接,也负责新连接的监控与处理。
2.能够将线程池中对应线程的eventloop对象分配出去。

如果线程池中线程的个数为0 ,则将主线程的Eventloop分配给新连接,进行监控与处理。
如果线程池中线程的个数有多个,则采用RR轮转思想,进行线程的分配。(就是将对应线程的Eventloop对象获取到然后分配给Connection)
将所有线程的Eventloop对象都存储起来,然后依次分配出去即可。

2.1成员变量

private:int _thread_count;                  // 要创建的线程的数量int _loop_idx;                      // 要分配的loop下标EventLoop *_baseloop;               // 主线程的loop,外界传入进来,如果要创建的从线程数据为0,那么就分配出去的就是主线程的loopstd::vector<LoopThread *> _threads; // 保存所有的LoopThread线程对象std::vector<EventLoop *> _loops;    // 保存所有线程对应的eventloop,然后依次分配出去。

2.2构造函数

线程的数量在初始化时不设置,由用户调用接口设置。
外界需要将主线程的baseloop对象传入进来,以防止线程池中没有线程。

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

2.3配置线程数量

void SetThreadCount(int count){_thread_count = count;}

2.4按照配置数量创建线程

创建线程时,将所有线程以及线程对应的eventloop对象都存储在数组中。
然后根据下标就可以依次分配线程对应的eventloop对象了。

 void CreateLoopThread(){if (_thread_count > 0) // 如果大于0就将所有的线程都创建出来,如果小于0,那么就必须要用主线程的baseloop。{_threads.resize(_thread_count);_loops.resize(_thread_count);for (int i = 0; i < _thread_count; i++){// 创建线程,并将所有的线程管理起来_threads[i] = new LoopThread();// 并保存管理所有线程对应的loop_loops[i] = _threads[i]->GetLoop();}}}

2.5依次分配Eventloop对象

如果线程池中线程的个数为0,这时候分配出去的eventloop对象就是主线程的baseloop对象。主线程eventloop既获取连接,也进行连接监控与处理。
否则就按照轮转形式依次分配出去。

 EventLoop *AssignLoop(){// 如果从线程的数量为0,那么分配出去的loop就是主线程对应的loopif (_thread_count == 0){return _baseloop;}_loop_idx = (_loop_idx + 1) % _thread_count;return _loops[_loop_idx];}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/87005.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/87005.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

华为云Flexus+DeepSeek征文|基于Dify构建文本/图像/视频生成工作流

华为云FlexusDeepSeek征文&#xff5c;基于Dify构建文本/图像/视频生成工作流 一、构建文本/图像/视频生成工作流前言二、构建文本/图像/视频生成工作流环境2.1 基于FlexusX实例的Dify平台2.2 基于MaaS的模型API商用服务 三、构建文本/图像/视频生成工作流实战3.1 配置Dify环境…

相机-IMU联合标定:IMU更新频率

文章目录 📚简介⚠️ IMU频率参数错误设置的影响❌ 相机-IMU联合标定失败:Optimization failed!🚀 确定IMU更新频率直接通过 rostopic hz 检查实际频率检查 IMU 驱动或数据手册从 bag 文件统计频率在这里插入图片描述修改 `update_rate` 的注意事项**最终建议****常见问题…

动手实践:如何提取Python代码中的字符串变量的值

要提取Python代码中所有变量类型为字符串的变量的值&#xff0c;但不执行代码&#xff08;避免安全风险&#xff09;&#xff0c;可以通过静态分析代码的抽象语法树&#xff08;AST&#xff09;来实现。以下是完整的解决方案&#xff1a; 本文由「大千AI助手」原创发布&#xf…

Python中字符串isalpha()函数详解

在 Python 中&#xff0c;isalpha() 是字符串&#xff08;string&#xff09;类型的内置方法&#xff0c;用于检查字符串中的所有字符是否都是字母字符&#xff08;alphabetic character&#xff09;。以下是详细说明&#xff1a; 一、基本功能 返回值&#xff1a;布尔值&…

Gradio全解13——MCP详解(4)——TypeScript包命令:npm与npx

Gradio全解13——MCP详解&#xff08;4&#xff09;——TypeScript包命令&#xff1a;npm与npx 第13章 MCP详解13.4 TypeScript包命令&#xff1a;npm与npx13.4.1 概念区分1. npm概念与运行逻辑2. npx概念及特点 13.4.2 操作示例1. 使用npm执行包2. 使用npx执行包3. 常用npm命令…

《推客小程序全链路开发指南:从架构设计到裂变运营》

在移动互联网流量红利逐渐消退的今天&#xff0c;如何低成本获客成为企业营销的核心痛点。推客小程序作为一种基于社交关系的裂变营销工具&#xff0c;正成为企业突破增长瓶颈的利器。本文将为您全面解析推客小程序的开发定制全流程&#xff0c;帮助您打造专属的社交裂变营销平…

中钧科技参加中亚数字经济对话会,引领新疆企业数字化新征程!

6月27 日&#xff0c;乌鲁木齐成为数字经济领域的焦点&#xff0c;中国新疆 - 中亚国家数字经济和数字贸易企业对话会在此盛大举行。 来自中亚国家及新疆数字经济领域的100 余位核心代表齐聚一堂&#xff0c;围绕数字经济时代的机遇、挑战与策略展开深度探讨。 本次对话会由新…

k8s一键部署tongweb企业版7049m6(by why+lqw)

声明 1.此贴仅供参考&#xff0c;请根据自身需求在测试环境测试和修改。 安装准备 1.获取对应的安装包和授权,并将授权和安装包放在同一个目录下 2.docekr已配置远程仓库 3.提前拉取jdk的镜像&#xff08;这里配置了使用openjdk:8&#xff09; 安装 将以下内容复制到k8s_…

Qt 与 Halcon 联合开发六:基于海康SDK设计完整的相机类【附源码】

在现代工业自动化、机器人视觉、等领域&#xff0c;相机模块的作用至关重要。通过相机模块采集到的图像数据&#xff0c;我们能够进行一系列的图像处理和分析。为了高效地控制相机和处理图像&#xff0c;本篇文章将介绍如何使用Qt和Halcon联合开发一个相机模块&#xff0c;帮助…

第7篇:Gin模板引擎——服务端页面渲染

作者:GO兔 博客:https://luckxgo.cn 分享大家都看得懂的博客 引言 在Web开发中&#xff0c;服务端页面渲染(SSR)依然是构建动态网页的重要方式。Gin框架虽然以API开发见长&#xff0c;但也内置了强大的模板引擎支持&#xff0c;基于Go标准库的html/template包实现。本文将深入…

RagFlow 源码部署启动指南

一、环境准备 1. 安装 uv 和 pre-commit 如果已安装&#xff0c;可跳过。推荐使用官方方式安装&#xff0c;避免报错&#xff1a; pipx install uv pre-commit export UV_INDEXhttps://mirrors.aliyun.com/pypi/simple安装报错 使用清华源安装&#xff1a; pipx install uv…

【Python基础】12 闲谈分享:Python用于无人驾驶的未来

引言&#xff1a;一个程序员的自动驾驶梦想 还记得2016年的那个秋天&#xff0c;我第一次坐进特斯拉Model S的驾驶座&#xff0c;体验Autopilot功能。当方向盘开始自己转动&#xff0c;车辆在高速公路上自动跟随前车时&#xff0c;我的内心涌起了一种奇妙的感觉——这不就是我…

为什么js是单线程?

js单线程&#xff0c;同一时间只能做一件事 。js的单线程 主要与它的用途有关。作为浏览器脚本语言&#xff0c;js的主要用途是与用户互动&#xff0c;以及操作DOM。这决定了它只能是单线程&#xff0c;否则会带来很复杂的同步问题。如果js同时有两个线程&#xff0c;一个线程在…

DVWA靶场通关笔记-文件包含(Medium级别 9种渗透方法)

目录 一、文件包含 1、原因 2、危害 3、防范措施 二、代码审计&#xff08;Medium级别&#xff09; 1、渗透准备 &#xff08;1&#xff09;配置php.ini &#xff08;2&#xff09;file1.php &#xff08;3&#xff09;file2.php &#xff08;4&#xff09;file3.php…

飞云翻倍布林(翻倍密码系统四线布林版)双安全系统+均价趋势指标+日线周线MACD,组合操盘技术图文分享

如上图组合操盘套装指标&#xff0c;主图指标-翻倍密码系统四线布林版-飞云翻倍布林。副图指标1-均价趋势指标&#xff0c;跟踪市场均价走势和趋势&#xff1b;副图指标2-日线周线MACD指标&#xff0c;跟踪日线和周线两个级别的MACD多空走势以及共振与否。 主图指标-飞云翻倍布…

《汇编语言:基于X86处理器》第6章 条件处理(1)

本章向程序员的汇编语言工具箱中引入一个重要的内容&#xff0c;使得编写出来的程序具备作决策的功能。几乎所有的程序都需要这种能力。首先&#xff0c;介绍布尔操作&#xff0c;由于能影响CPU状态标志&#xff0c;它们是所有条件指令的核心。然后&#xff0c;说明怎样使用演绎…

【分治思想】归并排序 与 逆序对

归并排序 归并排序是一种分治算法&#xff0c;怎么分&#xff0c;怎么治&#xff1f; 分&#xff1a;通过递归不断把数组分成两半&#xff0c;直到每个子数组只剩 1 个元素&#xff08;天然有序&#xff09;治&#xff1a;把两个已经排好序的子数组合并成一个有序数组。 把问…

SQL参数化查询:防注入与计划缓存的双重优势

在数据库操作中&#xff0c;SQL参数化查询&#xff08;Parameterized Queries&#xff09;是一种非常有效的技术&#xff0c;它不仅可以防止SQL注入攻击&#xff0c;还可以提高数据库查询的效率&#xff0c;尤其是在与计划缓存&#xff08;Query Plan Caching&#xff09;结合使…

【你怕一E1】- 孰轻孰重如何断-组合问题的多种情形

摘要 本视频讲解了组合问题的多种情形,包括多选一、多选二、多选三以及分队问题的解题方法。首先介绍了从不同人数中选人的不同选择方式,如一百人中选一人有一百种选择。随后,详细讲解了有序思考方法在多选二问题中的应用,通过选队长的方式列举不同组合情况,并归纳出选择规…

nginx反向代理的bug

nginx反向代理的bug 问题呈现 当我们配置反向代理的时候查询error.log的时候我们发现以下的问题 2025/06/29 08:38:47 [error] 7#7: *2 open() “/usr/share/nginx/html/payed/notify” failed (2: No such file or directory), client: 192.168.98.1, server: localhost, r…