【探索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,一经查实,立即删除!

相关文章

一键搭建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;如果我们将默认数据库的名字修改…

【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…

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; 缺少针对性的政府数字化转型年度培训规划 不清…

复旦大学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;帮助你快速掌握小程序…

专项:PID控制方法深究

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

《TCP/IP详解 卷一》第2章 Internet地址结构

目录 2.1 引言 2.2 表示IP地址 2.3 基本的IP地址结构 单播地址 全球单播地址&#xff1a; 组播地址 任播地址 2.4 CIDR和聚合 2.5 特殊用途地址 2.6 分配机构 2.7 单播地址分配 2.8 与IP地址相关的攻击 2.9 总结 2.1 引言 2.2 表示IP地址 IPv4地址&#xff1a;3…

【数据分享】不同共享社会经济路径下中国未来280个城市土地数量数据集(免费获取)

了解未来城市土地数量对于城市规划、社会经济发展和气候变化研究具有重要意义。通过分析不同共享社会经济路径下中国未来城市土地数量的数据&#xff0c;可以为未来城市发展趋势和可持续规划提供科学依据。 本次我们给大家带来的是不同共享社会经济路径下中国未来城市土地数量…

使用命令行创建文件夹和文件

创建文件夹 md 文件夹名字 创建文件 echo >文件名字.后缀然后回车即可 注意点:echo >文件名字.后缀 的 >后面不可以加空格&#xff0c;不然会报错\

Java基础之lambda表达式(五)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

《Python 语音转换简易速速上手小册》第9章 特定领域的语音处理(2024 最新版)

文章目录 9.1 语音处理在不同行业的应用9.1.1 基础知识9.1.2 主要案例:智能客服机器人案例介绍案例 Demo案例分析9.1.3 扩展案例 1:医疗语音助手案例介绍案例 Demo案例分析9.1.4 扩展案例 2:语言学习应用案例介绍案例 Demo

Python 实现Hash算法验证

目录 一、Hash 算法的原理及作用 二、python验证Hash算法代码实现 三、运行脚本验证如下 四、在线工具验证结果如下 五、总结 一、Hash 算法的原理及作用 Hash加密算法是一种将任意长度的消息压缩成固定长度散列值的算法。它的特点是快速、不可逆和安全。对于相同的消息&a…