【探索Linux】—— 强大的命令行工具 P.23(线程池 —— 简单模拟)

在这里插入图片描述

阅读导航

  • 引言
  • 一、线程池简单介绍
  • 二、Linux下线程池代码
    • ⭕Makefile文件
    • ⭕ . h 头文件
      • ✅Task.hpp
      • ✅thread.hpp
      • ✅threadPool.hpp
    • ⭕ . cpp 文件
      • ✅testMain.cpp
  • 三、线程池的优点
  • 温馨提示

引言

在Linux下,线程池是一种常见的并发编程模型,它能够有效地管理多个线程,提高系统的性能和资源利用率。通过线程池,可以实现多生产者多消费者模型,有效地处理并发任务,提升系统的响应速度和吞吐量。在本文中,我们将深入探讨如何在Linux环境下创建线程池,以及线程池的实现原理和使用技巧。通过深入理解线程池的概念和应用,我们可以更好地应对复杂的并发编程场景,从而提升系统的稳定性和性能表现。让我们一起探索Linux下线程池的奥秘,为并发编程的世界增添新的色彩!

一、线程池简单介绍

线程池是一种并发编程技术,用于管理和复用多个线程,以提高系统的性能和资源利用率。在线程池中,一定数量的线程被预先创建并保存在池中,当需要执行任务时,从线程池中选择一个空闲的线程来处理任务,任务执行完毕后,线程将返回到线程池中等待下一个任务。

通过使用线程池,可以避免频繁地创建和销毁线程,减少了线程创建和销毁的开销,同时也控制了并发线程的数量,避免系统资源被过度占用。线程池还可以根据系统负载情况动态调整线程数量,以更好地适应不同的工作负载。

二、Linux下线程池代码

⭕Makefile文件

thread_pool:testMain.cppg++ -o $@ $^ -std=c++11 -lpthread #-DDEBUG_SHOW
clean:rm -f thread_pool

这个 Makefile 包含了两个规则:一个用于编译名为"testMain.cpp"的程序并生成名为"thread_pool"的可执行文件,另一个用于清理生成的可执行文件。你可以使用"make"命令编译程序,使用"make clean"命令清理生成的可执行文件。

⭕ . h 头文件

✅Task.hpp

#pragma once#include <iostream>
#include <string>
#include <functional>// 定义函数类型 func_t,用于表示可以接受两个整型参数并返回一个整型结果的函数
typedef std::function<int(int, int)> func_t;// Task 类,表示一个任务
class Task
{
public:// 默认构造函数Task() {}// 带参数的构造函数,初始化任务的成员变量Task(int x, int y, func_t func) : x_(x), y_(y), func_(func){}// 重载 () 运算符,实现任务的执行void operator()(const std::string &name){// 在控制台输出任务执行的结果std::cout << "线程 " << name << " 处理完成, 结果是: " << x_ << "+" << y_ << "=" << func_(x_, y_) << std::endl;}public:int x_; // 任务的参数 xint y_; // 任务的参数 yfunc_t func_; // 保存任务所需执行的函数
};

✅thread.hpp

#pragma once
#include <iostream>
#include <string>
#include <cstdio>// 定义函数指针类型 fun_t,表示可以接受一个 void* 类型参数并返回一个 void* 类型结果的函数指针
typedef void *(*fun_t)(void *);// 线程数据结构,用于保存线程的参数和名称
class ThreadData
{
public:void *args_; // 线程参数std::string name_; // 线程名称
};// 线程类,用于创建和管理线程
class Thread
{
public:// 构造函数,初始化线程对象Thread(int num, fun_t callback, void *args) : func_(callback){// 设置线程名称为 "Thread-num"char nameBuffer[64];snprintf(nameBuffer, sizeof nameBuffer, "Thread-%d", num);name_ = nameBuffer;// 设置线程数据的参数和名称tdata_.args_ = args;tdata_.name_ = name_;}// 启动线程void start(){pthread_create(&tid_, nullptr, func_, (void*)&tdata_);}// 等待线程结束void join(){pthread_join(tid_, nullptr);}// 获取线程名称std::string name(){return name_;}// 析构函数~Thread(){}private:std::string name_; // 线程名称fun_t func_;       // 线程执行的函数指针ThreadData tdata_; // 线程数据pthread_t tid_;    // 线程 ID
};

✅threadPool.hpp

#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <unistd.h>
#include "thread.hpp"// 互斥锁类,封装了互斥锁的操作
class Mutex
{
public:Mutex(pthread_mutex_t *mtx) : pmtx_(mtx){}void lock(){pthread_mutex_lock(pmtx_);}void unlock(){pthread_mutex_unlock(pmtx_);}~Mutex(){}private:pthread_mutex_t *pmtx_;
};// RAII风格的加锁方式,构造时加锁,析构时解锁
class lockGuard
{
public:lockGuard(pthread_mutex_t *mtx) : mtx_(mtx){mtx_.lock();}~lockGuard(){mtx_.unlock();}private:Mutex mtx_;
};// 默认线程数
const int g_thread_num = 3;// 线程池类模板
template <class T>
class ThreadPool
{
public:// 获取互斥锁指针pthread_mutex_t *getMutex(){return &lock;}// 判断任务队列是否为空bool isEmpty(){return task_queue_.empty();}// 等待条件变量void waitCond(){pthread_cond_wait(&cond, &lock);}// 获取待执行任务T getTask(){T t = task_queue_.front();task_queue_.pop();return t;}private:// 构造函数,初始化线程池ThreadPool(int thread_num = g_thread_num) : num_(thread_num){pthread_mutex_init(&lock, nullptr);pthread_cond_init(&cond, nullptr);for (int i = 1; i <= num_; i++){threads_.push_back(new Thread(i, routine, this));}}ThreadPool(const ThreadPool<T> &other) = delete;const ThreadPool<T> &operator=(const ThreadPool<T> &other) = delete;public:// 获取线程池单例static ThreadPool<T> *getThreadPool(int num = g_thread_num){if (nullptr == thread_ptr){lockGuard lockguard(&mutex);if (nullptr == thread_ptr){thread_ptr = new ThreadPool<T>(num);}}return thread_ptr;}// 启动线程池中的线程void run(){for (auto &iter : threads_){iter->start();std::cout << iter->name() << " 启动成功" << std::endl;}}// 线程执行的函数static void *routine(void *args){ThreadData *td = (ThreadData *)args;ThreadPool<T> *tp = (ThreadPool<T> *)td->args_;while (true){T task;{lockGuard lockguard(tp->getMutex());while (tp->isEmpty())tp->waitCond();task = tp->getTask();}task(td->name_);}}// 向任务队列中添加任务void pushTask(const T &task){lockGuard lockguard(&lock);task_queue_.push(task);pthread_cond_signal(&cond);}// 析构函数,销毁线程池~ThreadPool(){for (auto &iter : threads_){iter->join();delete iter;}pthread_mutex_destroy(&lock);pthread_cond_destroy(&cond);}private:std::vector<Thread *> threads_; // 线程对象数组int num_; // 线程数量std::queue<T> task_queue_; // 任务队列static ThreadPool<T> *thread_ptr; // 线程池单例指针static pthread_mutex_t mutex; // 线程池单例的互斥锁pthread_mutex_t lock; // 线程池内部使用的互斥锁pthread_cond_t cond; // 线程池内部使用的条件变量
};// 静态成员初始化
template <typename T>
ThreadPool<T> *ThreadPool<T>::thread_ptr = nullptr;template <typename T>
pthread_mutex_t ThreadPool<T>::mutex = PTHREAD_MUTEX_INITIALIZER;

⭕ . cpp 文件

✅testMain.cpp

#include "threadPool.hpp" // 包含线程池头文件
#include "Task.hpp" // 包含任务类的头文件
#include <ctime>
#include <cstdlib>
#include <iostream>
#include <unistd.h>int main()
{srand((unsigned long)time(nullptr) ^ getpid()); // 初始化随机数种子// 获取线程池单例并运行线程ThreadPool<Task>::getThreadPool()->run();while(true){// 生产任务的过程,制作任务的时候,要花时间int x = rand() % 100 + 1; // 随机生成一个范围在1到100之间的整数xusleep(7721); // 模拟制作任务需要的时间int y = rand() % 30 + 1; // 随机生成一个范围在1到30之间的整数yTask t(x, y, [](int x, int y) -> int { // 创建任务对象t,执行加法操作return x + y;});std::cout << "制作任务完成: " << x << "+" << y << "=?" << std::endl; // 输出任务信息// 推送任务到线程池中ThreadPool<Task>::getThreadPool()->pushTask(t);sleep(1); // 暂停一秒钟}return 0;
}

这段代码主要实现了一个简单的任务生产者,不断地生成任务并将任务推送到线程池中执行。

三、线程池的优点

线程池能够有效地管理线程,提高系统的性能和响应速度,同时简化了线程管理的复杂性,是多线程编程中常用的一种技术。下面是它的优点

  1. 提高性能:线程池可以减少线程创建和销毁的开销,通过重用线程,避免了频繁地创建和销毁线程所带来的性能损耗。

  2. 控制并发度:线程池可以限制同时执行的线程数量,从而控制系统的并发度,防止因为过多线程导致系统资源被耗尽。

  3. 提高响应速度:由于线程池中的线程已经创建好并处于就绪状态,当任务到达时可以立即执行,从而减少了任务等待执行的时间,提高了系统的响应速度。

  4. 简化线程管理:线程池封装了线程的创建、销毁、调度等操作,简化了线程管理的复杂性,提高了代码的可维护性。

  5. 控制资源占用:线程池可以限制系统中同时存在的线程数量,从而控制系统对资源(如内存、CPU)的占用,防止资源被耗尽导致系统崩溃。

总而言之,线程池提供了一种高效、可控的线程管理机制,适用于处理大量并发任务的场景,是提高系统性能和响应速度的重要工具之一。

温馨提示

感谢您对博主文章的关注与支持!如果您喜欢这篇文章,可以点赞、评论和分享给您的同学,这将对我提供巨大的鼓励和支持。另外,我计划在未来的更新中持续探讨与本文相关的内容。我会为您带来更多关于Linux以及C++编程技术问题的深入解析、应用案例和趣味玩法等。如果感兴趣的话可以关注博主的更新,不要错过任何精彩内容!

再次感谢您的支持和关注。我们期待与您建立更紧密的互动,共同探索Linux、C++、算法和编程的奥秘。祝您生活愉快,排便顺畅!
在这里插入图片描述

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

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

相关文章

代码随想录算法训练营(动态规划2)| 62.不同路径 63. 不同路径 II

62.不同路径 本题大家掌握动态规划的方法就可以。 数论方法 有点非主流&#xff0c;很难想到。 leetcode题目链接 题目链接/文章讲解 视频讲解 二叉树的深度搜索&#xff0c;找到总共有几个叶子节点 这个想理解好难啊 //每个节点都是从左向右&#xff0c;然后回溯&#xff0c…

一键搭建Tex书写环境【免费、开源】

安装 # 安装 vscode scoop install extras/vscode # 安装 cmder(windows下超好用的命令行工具&#xff0c;可选) scoop install main/cmder-full # 安装 miktex scoop install main/miktex配置 将我的VSCode配置文件导入到 VSCode 即可。 VSCode for Latex 配置文件 具体步…

neo4j创建新数据库

根据网上提供的教程&#xff0c;neo4j并没有提供创建数据库的命令&#xff0c;其只有一个默认数据库graph.db&#xff0c;该数据库中的所有数据将存储在neo4j安装路径下的data/databases/graph.db目录中。 因此&#xff0c;我们猜想&#xff0c;如果我们将默认数据库的名字修改…

Qt:把文件夹从A移动到B

QT 文件复制&#xff0c;移动(剪切)操作_qt剪切文件到指定路径-CSDN博客 如何移动一个文件&#xff1f; QString old_nameQString("D:\\c\\c优秀源码学习.txt");QString new_nameQString("D:\\c优秀源码学习.txt");bool x QFile::rename(old_name,new_n…

【TypeScript基础知识点】的讲解

TypeScript基础知识点 TypeScript基础知识点 TypeScript基础知识点 TypeScript 是一种由 Microsoft 开发和维护的开源编程语言&#xff0c;它是 JavaScript 的一个超集&#xff0c;添加了可选的静态类型和基于类的面向对象编程&#xff0c;以下是一些 TypeScript 的基础知识点…

【C++】模板初阶 | 泛型编程 | 函数模板 | 类模板

目录 1. 泛型编程 2. 函数模板 2.1 函数模板概念 2.2 函数模板格式 2.3 函数模板的原理 2.4 函数模板的实例化 2.5 模板参数的匹配原则 3. 类模板 3.1 类模板的定义格式 3.2 类模板的实例化 【本节目标】 1. 泛型编程 2. 函数模板 3. 类模板 1. 泛型编程 如何实现一…

SpringCloud(16)之SpringCloud OpenFeign和Ribbon

一、Spring Cloud OpenFeign介绍 Feign [feɪn] 译文 伪装。Feign是一个轻量级的Http封装工具对象,大大简化了Http请求,它的使用方法 是定义一个接口&#xff0c;然后在上面添加注解。不需要拼接URL、参数等操作。项目主页&#xff1a;GitHub - OpenFeign/feign: Feign makes w…

车载测试面试:各大车企面试题汇总(含答案)

本博主协助百名人员成功进军车载行业 TBOX 深圳 涉及过T-BOX测试吗Ota升级涉及的台架环境是什么样的&#xff1f;上车实测之前有没有一个仿真环境台架环境都什么零部件T-BOX了解多少Linux和shell有接触吗 单片机uds诊断是在实车上座的吗 uds在实车上插的那口 诊断仪器是哪个…

java课设之简易版客房管理系统(mvc三层架构)

&#xff08;一&#xff09;、系统概述&#xff1a; 客房管理系统是一个用于管理酒店客房信息的程序&#xff0c;主要功能包括客房信息录入、客房状态查询、客房订单管理&#xff0c;客房的预定功能。 &#xff08;二&#xff09;、功能说明&#xff1a; 1.登录&#xff1a;管理…

如何在Linux部署OpenGauss数据管理系统并实现公网访问内网数据

文章目录 前言1. Linux 安装 openGauss2. Linux 安装cpolar3. 创建openGauss主节点端口号公网地址4. 远程连接openGauss5. 固定连接TCP公网地址6. 固定地址连接测试 前言 openGauss是一款开源关系型数据库管理系统&#xff0c;采用木兰宽松许可证v2发行。openGauss内核深度融合…

数字化转型导师坚鹏:如何制定政府数字化转型年度培训规划

如何制定政府数字化转型年度培训规划 ——以推动政府数字化转型战略落地为核心&#xff0c;实现知行果合一 课程背景&#xff1a; 很多政府都在开展政府数字化转型培训工作&#xff0c;目前存在以下问题急需解决&#xff1a; 缺少针对性的政府数字化转型年度培训规划 不清…

【pytorch】pytorch模型可复现设置

文章目录 序言1. 可复现设置代码2. 可复现设置代码解析2.1 消除python与numpy的随机性2.2 消除torch的随机性2.3 消除DataLoader的随机性2.4 消除cuda的随机性2.5 避免pytorch使用不确定性算法2.6 使用pytorch-lightning2.7 特殊情况 序言 为了让模型在同一设备每次训练的结果…

复旦大学MBA聚劲联合会:洞见智慧,拓宽思维格局及国际化视野

12月2日&#xff0c;“焕拥时代 俱创未来”聚劲联合会俱创会年度盛典暨俱乐部募新仪式圆满收官。16家复旦MBA俱乐部、200余名同学、校友、各界同仁齐聚复旦管院&#xff0c;一起在精彩纷呈的圆桌论坛里激荡思想&#xff0c;在活力四射的俱乐部风采展示中凝聚力量。      以…

08 Redis之集群的搭建和复制原理+哨兵机制+CAP定理+Raft算法

5 Redis 集群 2.8版本之前, Redis采用主从集群模式. 实现了数据备份和读写分离 2.8版本之后, Redis采用Sentinel哨兵集群模式 , 实现了集群的高可用 5.1 主从集群搭建 首先, 基本所有系统 , “读” 的压力都大于 “写” 的压力 Redis 的主从集群是一个“一主多从”的读写分…

海莲花APT组织样本跟踪分析

APT组织简介 OceanLotus(海莲花)APT组织是一个长期针对中国及其他东亚、东南亚国家(地区)政府、科研机构、海运企业等领域进行攻击的APT组织&#xff0c;该组织也是针对中国境内的最活跃的APT组织之一&#xff0c;该组织主要通过鱼叉攻击和水坑攻击等方法&#xff0c;配合多种…

计算机网络面经-HTTP的8种请求方式

简单介绍 HTTP是超文本传输协议&#xff0c;其定义了客户端与服务器端之间文本传输的规范。HTTP默认使用80端口&#xff0c;这个端口指的是服务端的端口&#xff0c;而客户端使用的端口是动态分配的。当我们没有指定端口访问时&#xff0c;浏览器会默认帮我们添加80端口。我们…

2.21日学习打卡----初学Nginx(一)

2.21日学习打卡 目录: 2.21日学习打卡一. Nginx是什么&#xff1f;概述Nginx 五大应用场景HTTP服务器正向代理反向代理正向代理与反向代理的区别&#xff1a;负载均衡动静分离 为啥使用Nginx? 二.下载Nginx&#xff08;linux&#xff09;环境准备下载Nginx和安装NginxNginx源码…

新手搭建服装小程序全攻略

随着互联网的快速发展&#xff0c;线上购物已经成为了人们日常生活中不可或缺的一部分。服装作为人们日常消费的重要品类&#xff0c;线上化趋势也日益明显。本文将详细介绍如何从零开始搭建一个服装小程序商城&#xff0c;从入门到精通的捷径&#xff0c;帮助你快速掌握小程序…

面试前端性能优化八股文十问十答第一期

面试前端性能优化八股文十问十答第一期 作者&#xff1a;程序员小白条&#xff0c;个人博客 相信看了本文后&#xff0c;对你的面试是有一定帮助的&#xff01;关注专栏后就能收到持续更新&#xff01; ⭐点赞⭐收藏⭐不迷路&#xff01;⭐ 1&#xff09;CDN的概念 CDN&…

专项:PID控制方法深究

1.前言 PID在工业界随处可见。其的原理是什么&#xff1f; 2.数学物理代表意义 PID全名为比例积分微分控制器。顾名思义&#xff0c;表明其由三个控制器组成。 一是P&#xff0c;其代表比例&#xff08;Proportional&#xff09;; 二是I&#xff0c;其代表积分&#xff08;I…