【linux多线程(四)】——线程池的详细解析(含代码)

2023-11-06

目录

什么是线程池?

线程池的应用场景 

线程池的实现

线程池的代码(C++) 
 


【linux线程(壹)】——初识线程(区分线程和进程,线程创建的基本操作)
【线程(二)】——互斥量的详细解析
【线程(三)】———条件变量的详细解析

什么是线程池?

线程池是一种线程使用模式,它是将一定数量线程和缓冲队列预存在一个池子中,池子中的线程轮流的往任务队列中拿去任务并完成任务,而任务队列往外开发一个接口,使其他线程能够往任务队列中推送任务。

线程池的优点:

线程池能够减少线程的创建和销毁所消耗的时间和系统资源的开销,如果不使用线程池,将可能造成系统创建大量的同类线程而导致消耗完内存或“过度切换”的问题。

线程池的应用场景 

1,需要大量线程来完成任务,且完成任务的时间较短,WEB服务器完成网页请求这样的任务使用线程池技术是非常合适的。因为单个任务小,而任务数量巨大,但对于长时间的任务,比如一个Telnet连接请求,线程池的优点不明显,因为Telnet会话时间比线程的创建时间太多了。

2.对性能苛刻要求的的应用,比如服务器迅速响应客户请求。

3.接受突发的大量请求时,但不至于使服务器创建大量的线程,在没有线程池情况下,将产生大量的线程,短时间内会产生大量的线程可能使内存达到极限,出现错误。

线程池的实现

线程池的成员变量:

  • 任务队列,quueu<T> q;
  • 线程个数,int num;
  • 互斥量,pthread_mutex_t lock;
  • 条件变量,pthread_cond_t cond;

创建线程池,需要创建一个任务队列和一定数量的线程。由于每次只能有一个线程进入队列中放任务和拿任务,所以此时需要定义一个互斥量进行维护,如果任务队列中的没有任务,此时线程就不能进入任务队列中,所以就创建一个条件变量。


 

线程池的代码(C++) 

 makefile文件

threadpool:threadpool.cc    
  g++ $^ -o $@ -lpthread                                                                                                                                     
    
clean:    
  rm -f threadpool

Task.hpp文件

#pragma  once    
#include<iostream>    
#include<stdio.h>    
using namespace std;    
class Task    
{    
  private:    
    int x;int y;    
    char op;                                                                                                                                                 
  public:       
    Task(int _x,int _y,char _op)    
      :x(_x)                        
      ,y(_y)    
      ,op(_op){ }    
    Task()           
    {};       
    void Run()    
    {             
      int ret=0;    
      switch(op){    
        case '+':    
          ret=x+y;    
          break;                     
        case '-':                    
          ret=x-y;                   
          break;                     
        case '*':            
          ret=x*y;
          break;
          case '/':
          ret=x/y;
          break;
          case '%':
          ret=x%y;
          break;
      }
      printf("%d %c %d = %d\n",x,op,y,ret);
    } 
};                                    

 threadpool.hpp文件 

#pragma once    
#include<iostream>                                                                                                                                           
#include<queue>    
#include<pthread.h>    
#include<unistd.h>    
using namespace std;    
    
    
#define NUM 4    
template<class T>    
class ThreadPool    
{    
  private:    
    queue<T> q;//任务队列    
    int thread_num;//线程池的线程数量    
    pthread_mutex_t lock;//互斥锁    
    pthread_cond_t cond;//条件变量    
  public:    
    ThreadPool(int num=NUM)//初始化变量
      :thread_num(num){    
        pthread_mutex_init(&lock,NULL);    
        pthread_cond_init(&cond,NULL);    
    }    
    
    bool Empty()    
    {    
      return q.size()==0?true:false;     
    }    
    
   static  void* Routine(void* arg)//线程执行流    
    {    
      pthread_detach(pthread_self());//线程分离    
      ThreadPool* self=(ThreadPool*)arg;
      while(1)
      {
        self->LockQueue();
        while(self->Empty())//任务队列是否为空
        {
          self->Wait();
        }
        T data;
        self->Pop(data);//取出任务
        self->UnlockQueue();

        cout<<pthread_self()<<"# ";                                                                                                                          
        //处理任务
        data.Run();//处理任务
        sleep(1);
      }
    }

    void Wait()//线程等待
    {
      pthread_cond_wait(&cond,&lock);
    }

    void LockQueue()//锁住队列
    {
      pthread_mutex_lock(&lock);
    }

    void UnlockQueue()//解锁队列
    {
      pthread_mutex_unlock(&lock);
    }

    void ThreadPoolInit()
    {
      pthread_t tid;
      for(int i=0;i<thread_num;i++)//创建线程池中的线程
      {
        pthread_create(&tid,NULL,Routine,(void*)this);
      }
    }

    void Push(const T& in)//将任务推进任务队列中
    {
      LockQueue();
      q.push(in);
      UnlockQueue();
      SignalThread();
    }

    void SignalThread()//唤醒cond变量下的线程
    {
      pthread_cond_signal(&cond);
    }

    void Pop( T& out)//取出任务队列中的任务
    {
      out=q.front();
      q.pop();
    }

    ~ThreadPool()
    {
      pthread_mutex_destroy(&lock);
      pthread_cond_destroy(&cond);
    }
};                      

threadpool.cc 文件

#include"threadpool.hpp"    
#include"Task.hpp"    
#include<time.h>    
#include<stdlib.h>    
int main()    
{    
  ThreadPool<Task> * q=new ThreadPool<Task>();//创建线程池    
  q->ThreadPoolInit();    
  srand((long int)time(NULL));    
  while(1)  //主线程往任务队列中放任务  
  {    
    char arr[]="+-*/%";    
    int x=rand()%100+1;    
    int y=rand()%100+1;    
    char op=arr[rand()%5];    
    Task t(x,y,op);//创建任务    
    q->Push(t);//将任务推送给队列中    
  }                                                                                                                                                          
  return 0;    
}  

运行结果:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【linux多线程(四)】——线程池的详细解析(含代码) 的相关文章

  • 在linux x86平台上学习ARM所需的工具[关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我有一个 x86 linux 机器 在阅读一些关于 ARM 的各种信息时 我很好奇 现在我想花一些时间学
  • Linux 源代码中的哪个位置会识别特定的 USB 设备?

    我有一个特定的 USB 设备 我想检查其 Linux 驱动程序源代码 我的理解是 USB 驱动程序执行的第一步是注册自己能够处理具有特定供应商 ID 和产品 ID 的设备 就我而言 供应商 ID 是0BDA产品 ID 是8187 有了这些信
  • C中的内存使用问题

    请帮忙 操作系统 Linux 其中 sleep 1000 中 此时 top 显示Linux任务 给我写了7 7 MEM使用 valgrind 未发现内存泄漏 我明白 写得正确 所有 malloc 结果都是 NULL 但是为什么这次 睡眠 我
  • 从命名管道读取

    我必须实现一个 打印服务器 我有 1 个客户端文件和 1 个服务器文件 include
  • libusb 和轮询/选择

    我正在使用 Linux 操作系统 想知道是否有任何文件描述符可以轮询 选择 当数据等待从 USB 设备读取时会触发这些文件描述符 我也在使用 libusb 库 但尚未找到可以使用的文件描述符 Use libusb 的轮询函数 http li
  • 使用 gatttool 或 bluepy BLE 订阅通知

    我正在使用 bluepy 编写一个程序 用于监听蓝牙设备发送的特征 我还可以使用任何库或语言 唯一的限制是在 Linux 上运行 而不是在移动环境中运行 似乎仅在移动设备中广泛使用 没有人在桌面上使用 BLE 使用 bluepy 我注册了委
  • 类似 wget 的 BitTorrent 客户端或库? [关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 是否有任何
  • 如何随时暂停 pthread?

    最近我开始将 ucos ii 移植到 Ubuntu PC 上 我们知道 在pthread的回调函数中的 while 循环中简单地添加一个标志来执行暂停和恢复是不可能模拟ucos ii中的 进程 的 如下解决方案 因为ucos ii中的 进程
  • 使用 linux perf 工具测量应用程序的 FLOP

    我想使用 perf Linux 性能计数器子系统的新命令行接口命令 来测量某些应用程序执行的浮点和算术运算的数量 出于测试目的 我使用了我创建的一个简单的虚拟应用程序 请参见下文 因为我找不到任何为测量 FP 和整数运算而定义的 perf
  • 当存在点和下划线时,使用 sed 搜索并替换

    我该如何更换foo with foo sed 只需运行 sed s foo foo g file php 不起作用 逃离 sed s foo foo g file php Example cat test txt foo bar sed s
  • 操作系统崩溃的常见原因[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我有兴趣了解 操作系统崩溃 不限于Windows崩溃 最常见的技术原因 从操作系统编程的角度 有哪些 我正在寻找一个不像 打开太多应用
  • 如何“grep”连续流?

    可以用吗grep在连续的流中 我的意思是有点tail f
  • bash双括号问题

    我对 bash 脚本非常陌生 在使用双括号时遇到了问题 我似乎无法让它们在 Ubuntu Server 11 10 中工作 我的下面的脚本位于 if test sh 中 bin bash if 14 14 then echo FOO fi
  • Bash 中 $() 和 () 之间的区别

    当我打字时ls l echo file 支架的输出 这只是简单的回显 被获取并传递到外部ls l命令 就等于简单的ls l file 当我打字时ls l echo file 我们有错误 因为不能嵌套 内部外部命令 有人可以帮助我理解之间的区
  • 从 Linux 命令行发送 SNMP 陷阱消息

    Folks 我需要从 Linux 命令行使用此命令 snmptrap 将自定义消息发送到陷阱侦听器 我需要根据用户设置在 v1 和 v2c 中发送相同的消息 这是我发现的 For v1 snmptrap v 1 c Tas hostname
  • 跟踪 pthread 调度

    我想做的是创建某种图表 详细说明 Linux 中 两个 线程的执行情况 我不需要查看线程的作用 只需查看它们何时被安排以及持续多长时间 基本上是一条时间线 在过去的几个小时里 我一直在互联网上搜索跟踪 pthread 调度的方法 不幸的是
  • 使用 C++ 输出字符串覆盖 Linux 终端上的最后一个字符串

    假设我有一个命令行程序 有没有办法让我说的时候 std cout lt lt stuff 如果我不做std cout lt lt n 在另一个之间std cout lt lt stuff 东西的另一个输出将覆盖同一行上的最后一个东西 清理行
  • 如何使用libaudit?

    我试图了解如何使用 libaudit 我想接收有关使用 C C 的用户操作的事件 我不明白如何设置规则 以及如何获取有关用户操作的信息 例如 我想获取用户创建目录时的信息 int audit fd audit open struct aud
  • Linux TCP服务器:在接受连接之前读取客户端的IP地址

    Related C Winsock API如何在接受连接之前获取连接客户端IP https stackoverflow com questions 716209 c winsock api how to get connecting cli
  • 如何使用 bash 脚本关闭所有终端,在每个终端中有效地按 Ctrl+Shift+Q

    我经常打开许多终端 其中一些正在运行重要的进程 例如服务器 而另一些则没有运行任何东西并且可以关闭 如果您按 重要 则会弹出确认提示Cntrl Shift Q在其中 如下所示 我想要一个 bash 脚本 它可以关闭所有终端 但将 重要 终端

随机推荐

  • 知识科普:什么是AGI?

    原文链接 最近ChatGPT大火 火到原来卖酒卖保险的人也都开始直播聊ChatGPT了 其中大家或多或少会提到一个词 AGI 看清楚不是GAI也不是AIGC 今天就和大家聊聊AGI是什么 AGI最近经常被提到 主要是因为ChatGPT的开发
  • 网络编程——TCP

    网络编程 TCP TCP编程 TCP是一种可靠的 基于连接的网络协议 它是面向字节流的 即从一个进程到另一个进程的二进制序列 一条TCP连接需要两个端点 这两个端点需要分别建立各自的套接字 通常一方用于发送请求和数据 称为客户端 另一方用于
  • Pickle 详解

    那么为什么需要序列化和反序列化这一操作呢 1 便于存储 序列化过程将文本信息转变为二进制数据流 这样就信息就容易存储在硬盘之中 当需要读取文件的时候 从硬盘中读取数据 然后再将其反序列化便可以得到原始的数据 在Python程序运行中得到了一
  • STM32开发(十九)STM32F103 数据手册 —— 低功耗模式解析

    上一篇 主目录 下一篇 文章目录 低功耗介绍 stm32 供电框图 低功耗模式 睡眠模式 停止模式 待机模式 低功耗模式汇总 低功耗介绍 系统复位或上电复位后 微控制器进入运行模式 在运行模式下 CPU通过HCLK提供时钟 并执行程序代码
  • Apollo学习笔记(21)图的深度优先遍历(DFS)和广度优先遍历(BFS)算法分析

    首先奉上大神链接 https www cnblogs com qzhc p 10291430 html 由于最近在看轨迹规划的资料 图遍历是基础 故拜读了大神的一些文章 在此记录 深度优先遍历 深度优先遍历 Depth First Sear
  • Vim常用操作快捷键记录

    经常忘记vim的一些操作快捷键 现在将其记录起来 方便以后查阅 这里定义以文本右方向为前 文本左方向为后 上下左右方向键 k j h l 以 字 为步长向前跳动 到达字首 w 以 字 为步长向后跳动 到达字首 b 以 字 为步长向前跳动 到
  • 共享计算机的网络凭证,win10设置共享文件夹时显示要网络凭证

    一 共享文件夹所在电脑设置 1 右键我的电脑 管理 系统工具 本地用户和组 用户 中间空白区域右键 新用户 2 输入自设的用户名和密码 如图勾选 创建 3 右键需要共享的文件见 安全 编辑 4 点击添加 5 输入新建的用户名 test 检查
  • 失业的程序员(九):正文篇:创业就是一场戏

    http www shenyisyn org 2013 04 23 tjp 2 htm 一 正文 跨入电商 说到我家人 我父母都是小学教师 对我从小管教无比严厉 他们希望我将来也能子承父业或者母业 并且更希望将来我的子女也能如此继承着 用句
  • 【1002】写出这个数

    题目链接 写出这个数 算法 include
  • 【数据集处理】WiderPerson介绍以及转YOLO格式(图片教程及代码----超详细)

    WiderPerson转YOLO格式 WiderPerson介绍 原论文中数据信息 下载后的文件样式 Annotations WiderPerson转YOLO 数据集下载地址 转格式以及选取类别 关于txt文件的处理 直接运行 生成yolo
  • 【网络安全】黑客自学笔记

    1 前言 作为一个合格的网络安全工程师 应该做到攻守兼备 毕竟知己知彼 才能百战百胜 计算机各领域的知识水平决定你渗透水平的上限 1 比如 你编程水平高 那你在代码审计的时候就会比别人强 写出的漏洞利用工具就会比别人的好用 2 比如 你数据
  • Feign远程调用注意事项

    Feign 远程查询失败 不需要回滚 CPU密集型和 IO密集型 CPU涉及的是计算能力 IO是文件读取类型的这种
  • 共识算法 --- PBFT、Raft和Paxos

    目录 一 Raft共识算法 1 什么是Raft 2 Raft的工作流程 3 Raft的相关应用 4 Raft的缺陷 5 Raft中三个子问题 5 1 Leader选举 Election 5 1 1 节点的三种角色 5 1 2 选举过程 5
  • 字节是真的难进,测开4面终上岸,压抑5个月,终于可以放声呐喊

    这次字节的面试 给我的感触很深 意识到基础的重要性 一共经历了五轮面试 技术4面 HR面 下面看正文 本人自动专业毕业 压抑了五个多月 终于鼓起勇气 去字节面试 下面是我的面试过程 很多面试题 都是靠记忆写的 希望能帮助到大家 致那些努力的
  • http各个版本的区别

    http进化史 http0 9 只有GET请求 也不支持请求头信息 请求信息只有下面一行 GET www baidu com http1 0 在请求中指定版本号 支持GET POST HEAD http1 1 http1 1新增了 OPTI
  • 进制压缩加密_token参数

    进制压缩加密 token参数 网址 https sh meituan com meishi c17 进入抓包 查看要获取的数据 可以在请求地址 找到 getPoiList 的请求链接 请求参数有多个 但是多次请求对比发现只有 token 参
  • LeetCode:118(Python)—— 杨辉三角(简单)

    杨辉三角 概述 给定一个非负整数 numRows 生成 杨辉三角 的前 numRows 行 在 杨辉三角 中 每个数是它左上方和右上方的数的和 输入 numRows 5 输出 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 输入
  • 超经典!分割任务数据集介绍。

    文章目录 前言 一 IRSTD 1k 二 Pascal VOC2012 1 数据简介 2 分割任务数据集介绍 三 iSAID 总结 前言 在探索网络的过程中 比较基础和重要的工作是了解数据 今天来总结下我目前使用过的分割任务数据集 本博文将
  • Linux进阶_DNS服务和BIND之实战案例篇

    成功不易 加倍努力 1 实战案例 实现DNS正向主服务器 2 实战案例 实现DNS从服务器 3 实战案例 实现DNS forward 缓存 服务器 4 实战案例 利用view实现智能DNS 5 实战案例 综合案例 实现Internet 的D
  • 【linux多线程(四)】——线程池的详细解析(含代码)

    目录 什么是线程池 线程池的应用场景 线程池的实现 线程池的代码 C linux线程 壹 初识线程 区分线程和进程 线程创建的基本操作 线程 二 互斥量的详细解析 线程 三 条件变量的详细解析 什么是线程池 线程池是一种线程使用模式 它是将