TinyWebSever源码逐行注释(三)_ thread_pool.cpp

前言

项目源码地址
项目详细介绍

项目简介:
Linux下C++轻量级Web服务器,助力初学者快速实践网络编程,搭建属于自己的服务器.

  1. 使用 线程池 + 非阻塞socket + epoll(ET和LT均实现) + 事件处理(Reactor和模拟Proactor均实现) 的并发模型
  2. 使用状态机解析HTTP请求报文,支持解析GET和POST请求
  3. 访问服务器数据库实现web端用户注册、登录功能,可以请求服务器图片和视频文件
  4. 实现同步/异步日志系统,记录服务器运行状态
  5. 经Webbench压力测试可以实现上万的并发连接数据交换

thread_pool.cpp用于配置web服务器的线程池,使用一个工作队列完全解除了主线程和工作线程的耦合关系:主线程往工作队列中插入任务,工作线程通过竞争来取得任务并执行它。主要内容如下:

  • 同步I/O模拟proactor模式
  • 半同步/半反应堆
  • 线程池

原项目地址的注释较少不适合初学者,于是我将每行都加上了注释帮助大家更好的理解:

#ifndef THREADPOOL_H
#define THREADPOOL_H#include <list>
#include <cstdio>
#include <exception>
#include <pthread.h>
#include "../lock/locker.h" // 包含自定义的锁机制(互斥锁和信号量)
#include "../CGImysql/sql_connection_pool.h" // 数据库连接池类,用于处理数据库连接// 定义一个线程池类,T是模板类型,表示任务的类型
template <typename T>
class threadpool
{
public:/* * 构造函数,初始化线程池 * actor_model 表示工作模式,connPool 是数据库连接池,thread_number 是线程池中的线程数,* max_request 是最大允许的请求队列长度*/threadpool(int actor_model, connection_pool *connPool, int thread_number = 8, int max_request = 10000);// 析构函数,释放线程池资源~threadpool();// 将新的请求任务添加到队列中,附带状态bool append(T *request, int state);// 将新的请求任务添加到队列中,不附带状态bool append_p(T *request);private:/* 工作线程运行的函数,它会不断从工作队列中取任务执行 */static void *worker(void *arg);// 实际处理任务的函数,从任务队列中取出任务并处理void run();private:int m_thread_number;        // 线程池中的线程数int m_max_requests;         // 请求队列中允许的最大请求数pthread_t *m_threads;       // 描述线程池的数组,其大小为 m_thread_numberstd::list<T *> m_workqueue; // 请求队列,用于存储需要处理的任务locker m_queuelocker;       // 保护请求队列的互斥锁,避免多线程同时访问时产生竞态条件sem m_queuestat;            // 信号量,表示是否有任务需要处理connection_pool *m_connPool;  // 数据库连接池,用于任务处理时的数据库操作int m_actor_model;          // 模型切换,表示不同的处理模式
};// 构造函数,初始化线程池
template <typename T>
threadpool<T>::threadpool(int actor_model, connection_pool *connPool, int thread_number, int max_requests): m_actor_model(actor_model), m_thread_number(thread_number), m_max_requests(max_requests), m_threads(NULL), m_connPool(connPool)
{// 如果线程数或请求数不合法,抛出异常if (thread_number <= 0 || max_requests <= 0)throw std::exception();// 动态分配线程数组m_threads = new pthread_t[m_thread_number];if (!m_threads)throw std::exception();// 循环创建线程,每个线程调用 worker 函数来执行任务for (int i = 0; i < thread_number; ++i){// 创建线程,worker 是线程的入口函数if (pthread_create(m_threads + i, NULL, worker, this) != 0){delete[] m_threads; // 创建线程失败,清理已分配的资源throw std::exception();}// 线程分离模式,线程结束后自动释放资源if (pthread_detach(m_threads[i])){delete[] m_threads;throw std::exception();}}
}// 析构函数,释放线程数组的资源
template <typename T>
threadpool<T>::~threadpool()
{delete[] m_threads;
}// 将请求任务加入请求队列,并指定任务的状态(读或写)
template <typename T>
bool threadpool<T>::append(T *request, int state)
{// 加锁,确保对队列的操作是线程安全的m_queuelocker.lock();// 如果请求队列已满,解锁并返回 falseif (m_workqueue.size() >= m_max_requests){m_queuelocker.unlock();return false;}// 设置请求的状态request->m_state = state;// 将请求添加到队列的末尾m_workqueue.push_back(request);// 解锁m_queuelocker.unlock();// 通知有新任务要处理m_queuestat.post();return true;
}// 将请求任务加入请求队列,不指定状态
template <typename T>
bool threadpool<T>::append_p(T *request)
{// 加锁,确保对队列的操作是线程安全的m_queuelocker.lock();// 如果请求队列已满,解锁并返回 falseif (m_workqueue.size() >= m_max_requests){m_queuelocker.unlock();return false;}// 将请求添加到队列的末尾m_workqueue.push_back(request);// 解锁m_queuelocker.unlock();// 通知有新任务要处理m_queuestat.post();return true;
}// 线程入口函数,线程从任务队列中取任务处理
template <typename T>
void *threadpool<T>::worker(void *arg)
{// 将传入的参数转换为线程池对象threadpool *pool = (threadpool *)arg;// 调用线程池的 run 函数,执行任务pool->run();return pool;
}// 处理任务的主函数,循环从请求队列中取任务并处理
template <typename T>
void threadpool<T>::run()
{while (true){// 等待有任务到来,信号量阻塞线程m_queuestat.wait();// 加锁以安全访问请求队列m_queuelocker.lock();// 如果队列为空,解锁并继续等待if (m_workqueue.empty()){m_queuelocker.unlock();continue;}// 从队列头取出一个请求T *request = m_workqueue.front();// 移除取出的请求m_workqueue.pop_front();// 解锁m_queuelocker.unlock();// 如果请求为空,继续处理下一个请求if (!request)continue;// 根据不同的 actor 模型处理请求if (1 == m_actor_model){// 读操作if (0 == request->m_state){// 调用 read_once 尝试读取数据if (request->read_once()){// 数据读取成功,标记为需要进一步处理request->improv = 1;// 使用数据库连接池处理数据库相关任务connectionRAII mysqlcon(&request->mysql, m_connPool);// 处理请求request->process();}else{// 数据读取失败,设置定时器标志request->improv = 1;request->timer_flag = 1;}}else{// 写操作if (request->write()){// 数据写入成功,标记为处理完成request->improv = 1;}else{// 数据写入失败,设置定时器标志request->improv = 1;request->timer_flag = 1;}}}else{// 如果使用另一种模型,不区分读写,直接处理connectionRAII mysqlcon(&request->mysql, m_connPool);request->process();}}
}
#endif

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

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

相关文章

Parsec问题解决方案

Parsec目前就是被墙了&#xff0c;有解决方案但治标不治本&#xff0c;如果想稳定串流建议是更换稳定的串流软件&#xff0c;以下是一些解决方案 方案一&#xff1a;在%appdata%/Parsec/config.txt中&#xff0c;添加代理 app_proxy_address 127.0.0.1 app_proxy_scheme http…

Event Bus实现兄弟组件通信

Event Bus实现兄弟组件通信 Event Bus&#xff08;事件总线&#xff09;是一种组件间通信的模式&#xff0c;主要用于非父子关系的组件之间的通信。它通过创建一个全局的 Vue 实例作为事件中心&#xff0c;任何组件都可以通过这个中心来触发事件或监听事件&#xff0c;从而实现…

Qt篇——Qt在msvc编译下提示“C2001:常量中有换行符“的错误

在pro文件中添加以下配置即可&#xff1a; msvc{QMAKE_CFLAGS /utf-8QMAKE_CXXFLAGS /utf-8 }

双指针(7)_单调性_三数之和

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 双指针(7)_单调性_三数之和 收录于专栏【经典算法练习】 本专栏旨在分享学习C的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 1. 题目…

Redis 常用命令总结

文章目录 目录 文章目录 1 . 前置内容 1.1 基本全局命令 KEYS EXISTS ​编辑 DEL EXPIRE TTL TYPE 1.2 数据结构和内部编码 2. String类型 SET GET MGET MSET SETNX INCR INCRBY DECR DECYBY INCRBYFLOAT 命令小结 内部编码 3 . Hash 哈希类型 HSET …

gpt4最新保姆级教程

如何使用 WildCard 服务注册 Claude3 随着 Claude3 的震撼发布&#xff0c;最强 AI 模型的桂冠已不再由 GPT-4 独揽。Claude3 推出了三个备受瞩目的模型&#xff1a;Claude 3 Haiku、Claude 3 Sonnet 以及 Claude 3 Opus&#xff0c;每个模型都展现了卓越的性能与特色。其中&a…

数据结构基本知识

一、什么是数据结构 1.1、组织存储数据 ---------》内存&#xff08;存储&#xff09; 1.2、研究目的 如何存储数据&#xff08;变量&#xff0c;数组....)程序数据结构算法 1.3、常见保存数据的方法 数组&#xff1a;保存自己的数据指针&#xff1a;是间接访问已经存在的…

【Vue】pnpm创建Vue3+Vite项目

初始化项目 &#xff08;1&#xff09;cmd切换到指定工作目录&#xff0c;运行pnpm create vue命令&#xff0c;输入项目名称后按需安装组件 &#xff08;2&#xff09;使用vs code打开所创建的项目目录&#xff0c;Ctrl~快捷键打开终端&#xff0c;输入pnpm install下载项目…

[概率论] 随机变量的分布函数 (一)

文章目录 1.随机变量的分布函数2.离散型随机变量的分布函数3.连续性随机变量的分布函数 1.随机变量的分布函数 设X XX是一个随机变量&#xff0c;x xx是任意实数&#xff0c;则函数 几何表示 性质&#xff08;一个函数是分布函数的充要条件&#xff09; 2.离散型随机变量的分布…

数据结构-图-存储-邻接矩阵-邻接表

数据结构-图-存储 邻接矩阵 存储如下图1,图2 图1 对应邻接矩阵 图2 #include<bits/stdc.h> #define MAXN 1005 using namespace std; int n; int v[MAXN][MAXN]; int main(){cin>>n;for(int i1;i<n;i){for(int j1;j<n;j){cin>>v[i][j];}}for(int…

深度解析Unix系统的基本概念及优缺点和原理

介绍 Unix系统是一种多用户、多任务、分时操作系统&#xff0c;起源于20世纪70年代初&#xff0c;由贝尔实验室开发。它具有强大的命令行接口和层次结构的文件系统&#xff0c;支持多种处理器架构&#xff0c;广泛应用于工程应用和科学计算等领域。 基本概念 一、Unix系统的起…

数据分析-15-时间序列异常检测及方法组合应用(案例实战)

参考异常值数据预警分析 1 异常检测 1.1 适用场景 异常检测算法适用的场景特点有: (1)无标签或者类别极不均衡; (2)异常数据跟样本中大多数数据的差异性较大; (3)异常数据在总体数据样本中所占的比例很低。 常见的应用案例如: 金融领域:从金融数据中识别”欺诈用…

数学建模强化宝典(13)M-K检验法

前言 M-K检验法&#xff0c;全称为Mann-Kendall检验法&#xff0c;是一种非参数的假设检验方法&#xff0c;广泛应用于时间序列数据的趋势性变化检验&#xff0c;特别是气候序列中的趋势分析和突变点检测。以下是对M-K检验法的详细介绍&#xff1a; 一、定义与背景 M-K检验法由…

嵌入式初学-C语言-数据结构--四

栈 1. 基本概念 栈是一种逻辑结构&#xff0c;是特殊的线性表。特殊在&#xff1a; 只能在固定的一端操作 只要满足上述条件&#xff0c;那么这种特殊的线性表就会呈现一种“后进先出”的逻辑&#xff0c;这种逻辑就被称为栈。栈 在生活中到处可见&#xff0c;比如堆叠的盘子…

Kubernetes部署(haproxy+keepalived)高可用环境和办公网络打通

HAProxy Keepalived 部署高可用性入口&#xff1a; 部署两台或多台节点运行 HAProxy 作为负载均衡器。使用 Keepalived 实现 VIP&#xff08;虚拟 IP&#xff09;&#xff0c;为 HAProxy 提供高可用性。Keepalived 会监控 HAProxy 的状态&#xff0c;如果主节点失效&#xff0…

Spring AOP,通知使用,spring事务管理,spring_web搭建

spring AOP AOP概述 AOP面向切面编程是对面向对象编程的延续&#xff08;AOP &#xff08;Aspect Orient Programming&#xff09;,直译过来就是 面向切面编程,AOP 是一种编程思想&#xff0c;是面向对象编程&#xff08;OOP&#xff09;的一种补充。&#xff09; 面向切面编…

【C++二分查找】1482. 制作 m 束花所需的最少天数

本文涉及的基础知识点 C二分查找 LeetCode1482. 制作 m 束花所需的最少天数 给你一个整数数组 bloomDay&#xff0c;以及两个整数 m 和 k 。 现需要制作 m 束花。制作花束时&#xff0c;需要使用花园中 相邻的 k 朵花 。 花园中有 n 朵花&#xff0c;第 i 朵花会在 bloomDay…

南京网站设计手机用的网站

近年来&#xff0c;随着移动互联网的快速发展&#xff0c;越来越多的用户通过手机浏览网页&#xff0c;这使得网站设计逐渐向移动端倾斜。在南京&#xff0c;网站设计特别注重适配手机端&#xff0c;这不仅是用户体验的提升&#xff0c;也是市场竞争的需要。一个响应式的网站能…

vue3 v-bind=“$attrs“ 的一些理解,透传 Attributes相关说明及事例说明

1、可能小伙伴们经常会在自己的项目中看到v-bind"$attrs"&#xff0c;这个一般是在自定义组件中看到。 比如&#xff1a; <template><BasicModalv-bind"$attrs"register"registerModal":title"getTitle"ok"handleSubm…

前端框架有哪些 如何选择和优缺点

前端框架是用于构建用户界面的工具和库&#xff0c;它们提供了一套预定义的组件、样式和交互模式&#xff0c;帮助开发者更高效地开发前端应用。目前市面上存在多种前端框架&#xff0c;每种框架都有其独特的优势和缺点。以下是一些常见的前端框架及其优势和缺点的概述&#xf…