线程池的设计

news2024/11/24 4:50:41

一.什么是线程池?

线程池就是创建若干个可执行的线程放到容器中,有任务处理时,会提交到线程池中的任务队列中,线程处理完不是销毁,而是阻塞等待下一个任务。

二.为何要使用线程池?

  • 降低资源消耗。重复利用创建好的线程减少线程创建和销毁造成的损耗。
  • 提高响应速度。当任务到来时,不用等待创建就可以立即执行

三.线程池的设计实现

1、线程池的内部结构主要由四部分组成

  •         1、第一部分是线程池管理器,它主要负责管理线程池的创建、销毁、添加任务等管理操作,它是整个线程池的管家。
  •         2、第二部分是工作线程,也就是图中的线程 t0~t9,这些线程勤勤恳恳地从任务队列中获取任务并执行。
  •         3、第三部分是任务队列,作为一种缓冲机制,线程池会把当下没有处理的任务放入任务队列中,由于多线程同时从任务队列中获取任务是并发场景,此时就需要任务队列满足线程安全的要求,所以线程池中任务队列采用 BlockingQueue 来保障线程安全。
  •          4、 第四部分是任务,任务要求实现统一的接口,以便工作线程可以处理和执行。

 C++实现一:

pthread_pool.hpp

#pragma once
#include <iostream>
#include <queue>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>

using std::endl;
using std::cin;
using std::cout;
using std::queue;

template<class T>
class PthreadPool {
public:
    PthreadPool(int num = 8)
        :_num(num) {
        pthread_mutex_init(&_lock, NULL);
        pthread_cond_init(&_cond, NULL);
    }
    ~PthreadPool() {
        pthread_mutex_destroy(&_lock);
        pthread_cond_destroy(&_cond);
    }
    void Lock() {
        pthread_mutex_lock(&_lock);             //上锁
    }
    void Unlock() {
        pthread_mutex_unlock(&_lock);           //解锁
    }
    void WakeUp() {                             //唤醒进程, 通知消费者线程有任务了
        pthread_cond_signal(&_cond);            //唤醒单个进程
    }
  void Wait() {                                 //没有任务, 消费者线程先阻塞起来等待任务
        pthread_cond_wait(&_cond, &_lock);      //条件变量要和一个锁关联起来才可以
    }
    bool IsEmptyQueue() {
        return _taskqueue.empty();
    }
    static void* Routine(void* args)
    {
        PthreadPool* self = (PthreadPool*)args;
        while (1) {
            self->Lock();
            while (self->IsEmptyQueue()) {       //while  防止伪唤醒,
                //wait
                self->Wait();
            }
            //说明存在 task了/
            T t;
            self->PopTask(t);
            self->Unlock();
            t.Run();                            //解锁后处理任务.... 做啥???
        }
    }
    void PushTask(const T& in) {                //传入参数, push task
        Lock();
        _taskqueue.push(in);                    //操作临界资源加锁
        Unlock();
        WakeUp();
    }
    void PopTask(T& out) {                       //传出参数 拿取任务
        out = _taskqueue.front();                //拿取pop任务
        _taskqueue.pop();                        //任务队列pop 任务
    }
    void InitPthreadPool() {
        pthread_t tid;
        for (int i = 0; i < _num; ++i) {
            pthread_create(&tid, NULL, Routine, this);
            pthread_detach(tid);                 //回收线程资源
        }
    }

private:
    int _num;                                   //工作线程的数目
    queue<T> _taskqueue;                        //任务队列
    pthread_mutex_t _lock;                      //锁保证临界资源的互斥访问
    pthread_cond_t _cond;                       //条件变量控制资源到来时候的唤醒工作
};

task.hpp

#pragma once
#include <iostream>
#include <pthread.h>
using std::endl;
using std::cout;
using std::cerr;
//typedef int (*handler_t ) (int, int, char);

class Task {
public:
    Task(int x = 1, int y = 1, char op = '+')                //默认构造
        : _x(x)
        , _y(y)
        , _op(op)
    {}
    ~Task(){}
    void Run()
    {
        int z = 0;
        switch(_op)
        {
            case '+':
               {
                    z = _x + _y;
                    break;
                }
            case '-':
            {
                z = _x - _y;
                break;
            }
            default:
            {
                cerr << "not support operator!" << endl;
                break;
            }
        }
        cout << "thread: [" << pthread_self() << "]: "<< _x << _op << _y << "=" << z << endl;
    }

private:
    int _x;
    int _y;
    char _op;
};

main.cpp

   PthreadPool<Task> * tp = new PthreadPool<Task>();
    tp->InitPthreadPool();
    srand((unsigned long)time(nullptr));
    const char* ops = "+-*/%";
    while (1) {
        int x = rand() % 123 + 1;
        int y = rand() % 123 + 1;
        Task t(x, y, ops[rand() % 5]);
        tp->PushTask(t);
    sleep(1);
    }

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

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

相关文章

NLP原理和应用入门:paddle(梯度裁剪、ONNX协议、动态图转静态图、推理部署)

目录 一、梯度裁剪 1.1设定范围值裁剪 1. 全部参数裁剪&#xff08;默认&#xff09; 2. 部分参数裁剪 1.2 通过L2范数裁剪 1.3通过全局L2范数裁剪 二. 模型导出ONNX协议 三、动态图转静态图 3.1两种图定义 3.2 什么场景下需要动态图转静态图 3.3为什么动态图模式越来…

k8s 部署 seata1.6.0 集群 基于 nacos 注册中心 + mysql 数据库

k8s 部署 seata1.6.0 集群 基于 nacos 注册中心 mysql 数据库 大纲 1 镜像制作2 准备configmap3 准备deploy 部署文件4 部署seata到k8s 镜像制作 下载seata 选择1.6.0。下载后得到 seata-server-1.6.0.zip 已经上传到百度云盘 下载地址&#xff1a;http://seata.io/zh-cn…

Maven 依赖下载失败解决方案——配置国内源 + 具体解决办法

目录 前言 一、配置 Maven 国内源 二、重新下载jar包 三、其他问题 前言 最近发现 spring-boot 框架更新到 2.7.11 了&#xff0c;由于以前一直使用的是 2.7.9 &#xff0c;所以一直出现依赖下载失败的问题&#xff0c;实际上这是由于 IDEA 会先加载之前下载好的依赖&#xf…

openharmony内核中不一样的双向链表

不一样的双向链表 链表初识别遍历双向链表参考链接 链表初识别 最近看openharmony的内核源码时看到一个有意思的双向链表&#xff0c;结构如下 typedef struct LOS_DL_LIST{struct LOS_DL_LIST *pstPrev; //前驱节点struct LOS_DL_LIST *pstNext; //后继节点 }LOS_DL_LIST;不…

FPGA入门系列12--RAM的使用

文章简介 本系列文章主要针对FPGA初学者编写&#xff0c;包括FPGA的模块书写、基础语法、状态机、RAM、UART、SPI、VGA、以及功能验证等。将每一个知识点作为一个章节进行讲解&#xff0c;旨在更快速的提升初学者在FPGA开发方面的能力&#xff0c;每一个章节中都有针对性的代码…

Spring IOC DI - 整合MyBatis

Spring IOC目录 主要内容Spring 框架介绍Spring 框架的优势(对比以前项目的缺点)Spring 框架引入历史发展框架学习三要素Spring 模块介绍 Spring IoC/DI - 引入IoC/DI 概念辨析使用IoC/DI的好处IoC/DI具体应用场景 Spring IoC/DI - 代码实现环境准备Spring 框架环境搭建创建Mav…

图的遍历和应用

文章目录 图的遍历深度优先遍历对于无向图的邻接矩阵的深度优先遍历无向非连通图的深度优先遍历 对于无向图的邻接表的深度优先遍历非递归实现深度优先遍历无向图的邻接矩阵代码实现无向图的邻接表代码实现递归和非递归的同异 广度优先遍历邻接表BFS邻接矩阵BFS 图的应用生成树…

Android 拍照以及相册中选择(适配高版本)————上传头像并裁剪(一)

前言 在项目研发中&#xff0c;相信大家都遇到过给用户增加头像照片的需求。 随着手机版本的不断更新&#xff0c;android 8、android 9、android 10、android 12、android 13、鸿蒙系统等等&#xff1b;遇到这个功能需求&#xff0c;大家肯定会想&#xff0c;“这还不好写&…

“双碳”目标下二氧化碳地质封存技术应用前景及模型构建实践方法

二氧化碳地质封存技术起步较晚&#xff0c;目前仍没有一套相对完整的行业规范&#xff1b;且就该技术而言&#xff0c;涉及环节众多&#xff0c;理论相对复杂&#xff0c;对于行业的新入局者不太友好。因此&#xff0c;结合时代背景&#xff0c;我们首次尝试对二氧化碳地质封存…

【裸金属服务器】安装VMware ESXi

官方安装操作ESXi地址 一、虚拟化服务器分类&#xff1a; 寄居架构&#xff08;Hosted Architecture&#xff09;和裸金属架构&#xff08;Bare Metal Architecture&#xff09;。 1、寄居架构&#xff08;Hosted Architecture&#xff09;&#xff1a;在操作系统之上安装和运…

8.系统日志

1.api访问日志 对应数据库 拦截器 拦截逻辑 ApiAccessLogFilter类的createApiAccessLog方法 buildApiAccessLogDTO方法就是完善实体类&#xff0c;把接口执行时长之类的填充完整。 然后就是保存日志到infra_api_access_log数据库。 过滤器注册生效 2.api错误日志 对应数…

Windows 程序开机自启动速度优化,为什么腾讯会议自启动速度那么高?

目录 一、问题的说明和定义 二、问题的分析 1.问题初步分析 2.详细的分析&#xff1a; 2.1Windows常见的自启动方式 2.2Windows常见的自启动方式的细节分析 三、问题的解决方案 1、为什么腾讯会议Rooms那么快 2.我们是否可以跟腾讯会议一样快 一、问题的说明和定义 这…

Vue之插件的定义和使用

概述 学习本文之前&#xff0c;我们需要弄清楚何为插件&#xff1f;插件其实就是一段扩展程序&#xff0c;主要目的是用于扩展功能。就比如Idea家族和VSCode家族的插件&#xff0c;它们也是一段扩展程序&#xff0c;将其安装到IDE中就可以使用插件里面实现的功能了&#xff0c…

SCADA平台的HMI功能

01 前言 虹科Panorama SCADA平台支持桌面HMI、Web HMI和移动HMI的功能。桌面HMI主要是在桌面工作站实现数据可视化&#xff0c;能够获取到最全面的数据信息以及实现功能&#xff1b;Web HMI可以通过在软件中添加Web HMI服务器&#xff0c;运行程序后&#xff0c;可以在Web 客户…

HTML5基础知识总结总结(详细,附带源代码)

HTML5基础知识 一&#xff1a;前言二&#xff1a; HTML基本结构。三&#xff1a;基本标签3.1 h标签3.2 p标签3.3 hr标签3.4 br标签3.5 strong标签与em标签3.6 特殊符号3.7 运行效果 三&#xff1a;图像标签四&#xff1a;链接标签五&#xff1a;列表六&#xff1a;表格七&#…

Allegro PCB后处理和生产文件导出

Allegro PCB后处理&#xff0c;主要是完成线路设计以后&#xff0c;输出生产文件之前的处理。部分是看教程做的记录&#xff0c;方便以后自己参考。 教程&#xff1a; [小哥Cadence Allegro 132讲字幕版PCB视频教程]_哔哩哔哩_bilibili 感觉关键是多看右边Options菜单&#xf…

【15】SCI易中期刊推荐——电子电气 | 仪器仪表(中科院4区)

💖💖>>>加勒比海带,QQ2479200884<<<💖💖 🍀🍀>>>【YOLO魔法搭配&论文投稿咨询】<<<🍀🍀 ✨✨>>>学习交流 | 温澜潮生 | 合作共赢 | 共同进步<<<✨✨ 📚📚>>>人工智能 | 计算机视觉…

[NISACTF 2022]level-up

[NISACTF 2022]level-up f12 发现提示disallow 也就是不允许的想到robots.txt LEVEL_2 <?php //here is level 2 error_reporting(0); #屏蔽报错信息 include "str.php"; #包含str.php这个页面 if (isset($_POST[array1]) && isset($_POST[arr…

巧用千寻位置GNSS软件|如何快速完成道路桥涵放样

道路桥涵放样主要解决道路施工中正交、斜交涵洞的测量&#xff0c;正交涵洞放样是中心线的定线放样&#xff1b;斜交涵洞放养是涵洞中心线与线路成一固定夹角的情况下的放样。 那么如何运用千寻位置GNSS软件实现道路桥涵放样呢&#xff1f;下面为各位一一介绍。 点击【测量】-&…

【移动端网页布局】移动端网页布局基础概念 ⑨ ( webkit 内核 | 移动端网页 CSS 初始化 - normalize.css )

文章目录 一、webkit 内核二、移动端网页 CSS 初始化 - normalize.css 一、webkit 内核 移动端浏览器 都是 基于 webkit 内核的 , QQ 浏览器 / 百度 / Safari / UC 都是基于 webkit 内核的 ; 移动端网页布局需要 兼容 普通浏览器 与 webkit 浏览器 ; webkit 内核浏览器 对 HT…