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

news/2024/9/19 12:10:20/ 标签: c++, web, 服务器, linux, tcp/ip, php
webkit-tap-highlight-color: rgba(0, 0, 0, 0);">

前言

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

项目简介:
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.ppmy.cn/news/1523314.html

相关文章

python基础语法四-数据可视化

书接上回&#xff1a; python基础语法一-基本数据类型 python基础语法二-多维数据类型 python基础语法三-类 1. plot函数绘制简单折线图 (1)需要的模块&#xff1a;matplotlib.pyplot (2)语法&#xff1a;matplotlib.pyplot.plot(x, y, format_string, **kwargs) x: x轴数…

C语言程序设计-练习篇

不知道结果仍义无反顾地才是勇士。 三&#xff0c;打印整数二进制的奇数位和偶数位 题目内容&#xff1a; 获取一个整数二进制序列中所有的奇数位和偶数位&#xff0c;分别打印出二进制序列 #include <stdio.h>//打印整数二进制的奇数位和偶数位 int main() {int i 0…

C语言从头学55——学习头文件errno.h、float.h

1、头文件 errno.h 中的变量 errno 的使用 在 errno.h 定义了一个 int 类型的变量 errno&#xff08;错误码&#xff09;&#xff0c;如果发现这个变量出现非零值&#xff0c;表示已经执行的函数发生了错误。这个变量一般多用于检查数学函数运算过程中发生的错误。 …

Vue面试题——项目介绍以及SPA介绍

谈谈你开发的项目背景与、架构和技术栈 项目背景 假设我们正在开发一个名为“智慧旅游助手”的Web平台。该平台旨在为用户提供一站式的旅游服务&#xff0c;包括目的地推荐、酒店预订、行程规划、在线购票&#xff08;如门票、机票&#xff09;、旅游攻略分享以及基于地理位置…

不到200行代码,一键写出简单贪吃蛇网页游戏!附详细代码!快来看看吧!

​哈喽大家好&#xff0c;这里是大白百宝阁&#xff0c;每天分享一段小代码~ 今天要分享的是&#xff0c;不到200行代码&#xff0c;制作html版贪吃蛇&#xff0c;效果如下&#xff1a; 游戏结束后&#xff0c;还会显示&#xff1a; 代码如下&#xff1a; <!DOCTYPE html&g…

传统CV算法——边缘算子与图像金字塔算法介绍

边缘算子 图像梯度算子 - Sobel Sobel算子是一种用于边缘检测的图像梯度算子&#xff0c;它通过计算图像亮度的空间梯度来突出显示图像中的边缘。Sobel算子主要识别图像中亮度变化快的区域&#xff0c;这些区域通常对应于边缘。它是通过对图像进行水平和垂直方向的差分运算来…

基于Java+SpringBoot+Vue+MySQL的美容美发管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 基于SpringBootVue的美容美发管理系统【附源码文档】、前后…

【Visual Studio 报错】vs 在使用二进制写入文件时弹窗报错:使用简体中文 gb2312 编码加载文件

如以下报错 解决办法 解决方法&#xff1a;文件->高级保存选项->将文件编码形式改为“UTF-8带签名” 若找不到高级保存选项&#xff0c;可以跟着下面路径把该选项调出来 &#xff1a;工具->自定义->命令->菜单栏中改成文件->预览右边点添加命令->类别中…

第二证券:涨停潮!传手机将使用钛金属外壳?

今天早盘&#xff0c;银行股再度重挫&#xff0c;导致上证指数、上证50纷乱创出阶段性新低&#xff0c;上证指数跌破2800点&#xff0c;小盘成长股则大面积反弹&#xff0c;创业板指、科创50等股指飘红。 盘面上&#xff0c;新式烟草、钛金属、锂矿、玻璃基板等板块涨幅居前&a…

全球性“微软蓝屏”事件的深思:网络安全与系统稳定性的挑战与应对

近日&#xff0c;由于微软视窗系统软件更新引发的全球性“微软蓝屏”事件&#xff0c;成为科技领域的热点新闻。这次事件不仅影响了全球约850万台设备&#xff0c;波及航空、医疗、传媒等关键行业&#xff0c;还导致美国超过2.3万架次航班延误。如此规模的系统中断&#xff0c;…

【Shiro】Shiro 的学习教程(三)之 SpringBoot 集成 Shiro

目录 1、环境准备2、引入 Shiro3、实现认证、退出3.1、使用死数据实现3.2、引入数据库&#xff0c;添加注册功能后端代码前端代码 3.3、MD5、Salt 的认证流程 4.、实现授权4.1、基于角色授权4.2、基于资源授权 5、引入缓存5.1、EhCache 实现缓存5.2、集成 Redis 实现 Shiro 缓存…

qt怎么格式化字符串?

在Qt中&#xff0c;格式化字符串可以通过多种方式实现&#xff0c;主要依赖于你的具体需求和上下文。下面列出了一些常见的方法&#xff1a; 1. 使用QString的arg()方法 QString类提供了arg()方法&#xff0c;这个方法允许你插入值到字符串中的占位符位置。占位符由%1、%2等表…

详细步骤!分享6款AI论文写作助手自动生成器实例操作!

在当今学术研究和写作领域&#xff0c;AI论文生成工具的出现极大地提高了写作效率和质量。这些工具不仅能够帮助研究人员快速生成论文草稿&#xff0c;还能进行内容优化、查重和排版等操作。以下是6款推荐的AI论文写作助手自动生成器实例操作&#xff0c;特别推荐千笔-AIPassPa…

pytorch张量运算的广播机制

PyTorch 的广播机制&#xff08;broadcasting&#xff09;是指在进行张量运算时&#xff0c;自动扩展较小张量的形状以匹配较大张量的形状&#xff0c;使它们能够进行逐元素运算。广播机制避免了手动扩展张量的繁琐过程&#xff0c;并且在不增加内存开销的情况下进行高效计算。…

黑马点评16——多级缓存-JVM进程缓存

文章目录 什么是多级缓存导入商品案例初识Caffeine实现进程缓存 什么是多级缓存 但是现在的nginx的压力太大了&#xff0c;所以nginx也要部署成集群 当然我们的redis、tomcat都可以部署成集群 导入商品案例 我们在docker中开启了一个mysql的数据库&#xff0c;里面配置了一个…

如何从 Bak 文件中恢复 SQL数据库?(3种方法)

如何从 .bak 文件恢复 SQL数据库&#xff1f; 在数据库管理和维护过程中&#xff0c;数据的安全性和完整性至关重要。备份文件&#xff08;.bak 文件&#xff09;是 SQL Server 中常用的数据库备份格式&#xff0c;它包含了数据库的完整副本&#xff0c;用于在数据丢失、系统故…

为什么有的单位将SCI-E看作EI核心?

将SCI-E&#xff08;Science Citation Index Expanded&#xff0c;即SCI扩展版&#xff09;看作EI&#xff08;Engineering Index&#xff0c;工程索引&#xff09;核心期刊的现象&#xff0c;主要源于不同单位对学术成果评价标准和体系的差异&#xff0c;以及对国际学术数据库…

QWidget(c++)嵌入window环境的exe

QWidget(c)嵌入window环境的exe 我用的msvc2017 64bit编译器会报这个错误 visual.obj:-1: error: LNK2019: __imp_FindWindowW "public: __cdecl Visual::Visual(class QWidget *)" (??0VisualQEAAPEAVQWidgetZ)然后改成minGw 64bit 就不会报错 #ifndef VISUAL_…

SprinBoot+Vue二手回收微信小程序的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue3.6 uniapp代码 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍&#xff1a;CSDN认证博客专家&#xff0c;CSDN平…

网络ACL详解-从原理到实战模拟

引言 在复杂多变的网络环境中&#xff0c;保障网络安全和数据传输的合法性、高效性至关重要。访问控制列表&#xff08;Access Control Lists&#xff0c;简称ACL&#xff09;作为网络安全的重要组成部分&#xff0c;广泛应用于各种网络设备中&#xff0c;用以控制网络流量的流…