当前位置: 首页 > news >正文

C++实现一个线程池

原文链接:C++实现一个线程池

介绍

线程池是提高CPU利用率的一个非常高效的方法,线程池就是通过预先创建多个线程,当有任务时就执行,无任务时就阻塞.

相比一般的多线程方法,线程池更加简单,模块化,并且效率更高,因为不会重复创建删除线程.

预备知识

异步线程(包括future,packaged_task等对象): 创建异步返回的线程

wrapper装饰器(function+bind): 实现函数封装,泛型编程

condition_variable条件变量: 线程池任务分发和执行的条件控制

shared_ptr智能指针: 优化内存管理

类型推导和后置返回类型: 怎么实现泛型下正确返回未知类型

完美转发: 了解如何实现完美转发

线程池逻辑实现

#include<iostream>
#include<queue>
#include<functional>
#include<condition_variable>
#include<vector>
#include<thread>
#include<future>
#include<atomic>class ThreadPools{
public:ThreadPools(int n_threads): stop(false){for(int i=0;i<n_threads;i++){workers.emplace_back([this](){// 每个线程构造函数while(true){int task;{   //锁的作用域std::unique_lock<std::mutex> lock(this->mtx); //获取队列锁//判断队列非空或者线程池stop则返回.this->cv.wait(lock,[this](){return this->stop||!this->tasks.empty();});if(this->stop&&this->tasks.empty()) return ;// 如果线程池stop且队列空,结束线程.task=this->tasks.front();this->tasks.pop();}std::cout<<"run task:"<< task<<"\n";}    });}};~ThreadPools(){{std::unique_lock<std::mutex> lock(mtx);stop=true;}cv.notify_all();//注意必须是 &work引用参数形式, 线程不允许复制构造for(std::thread &work: workers){ work.join();}std::cout<<"thread pools final stop\n";};void enqueue(int task){{std::unique_lock<std::mutex> lock(mtx);if(stop){std::cout<<"push to a stop pools\n";return ;}tasks.push(task);}std::cout<<"push task:"<< task<<"\n";cv.notify_one();return ;};private:std::vector<std::thread> workers;std::queue<int> tasks;std::condition_variable cv;std::mutex mtx;std::atomic<bool> stop;
};int main(){ThreadPools pools(2);for(int i=0;i<10;i++) pools.enqueue(i);return 0;

简单线程池

实现一个线程池,并执行三种任务: 有参无返回值任务,有参有返回值任务 和 有参返回消息结构体任务

#include<thread>
#include<functional>
#include<future>
#include<condition_variable>
#include<memory>
#include<iostream>
#include<mutex>
#include<atomic>
#include<vector>
#include<queue>
#include<type_traits>
#include<cstring>class ThreadPools{
public:ThreadPools(int n_threads): n_threads(n_threads),stop(false){for(int i=0;i<n_threads;i++){workers.emplace_back([this](){while(true){std::packaged_task<void()> task;{std::unique_lock<std::mutex> lock(this->mtx);this->cv.wait(lock,[this](){return this->stop || !this->tasks.empty();});if(this->stop && this->tasks.empty()) return ;task=std::move(this->tasks.front());this->tasks.pop();}task();//std::cout<<"run a task, "<<"current tasks size="<<tasks.size()<<"\n";}});}}~ThreadPools(){{std::unique_lock<std::mutex> lock(mtx);stop=true;}cv.notify_all();for(std::thread &worker : workers){worker.join();}//std::cout<<"thread pools terminated\n";}template<typename F>auto enqueue(F&& f)->std::future<typename std::result_of<F()>::type>;private:int n_threads;std::atomic<bool> stop;std::vector<std::thread> workers;std::queue<std::packaged_task<void()>> tasks;std::condition_variable cv;std::mutex mtx;
};template<typename F>
auto ThreadPools::enqueue(F&& f)->std::future<typename std::result_of<F()>::type>{using return_type=typename std::result_of<F()>::type;auto task=std::make_shared<std::packaged_task<return_type()>>(std::forward<F>(f));std::future<return_type> res=task->get_future();{std::unique_lock<std::mutex> lock(mtx);if(stop){throw std::runtime_error("enqueue on stopped ThreadPool");}tasks.emplace([task](){(*task)();});}cv.notify_one();//std::cout<<"push a task, "<<"current tasks size="<<tasks.size()<<"\n";return res;
}class Message{
public:Message(int fd,int from,int to,std::string& content): fd(fd),from(from),to(to),content(content){size=content.size();}int fd;int from;int to;int size;std::string content;
};int main(){ThreadPools tp(3);// 无返回值任务for(int i=0;i<10;i++){tp.enqueue([i](){std::cout<<"task "<<i<<"\n";});}// 有返回值任务, 正常来讲,返回值是每回轮询,不是等待.std::vector<std::future<int>> results;for(int i=0;i<10;i++){auto f=[](int i) { return i * i; };std::function<int()> bf=std::bind(f,i);results.push_back(tp.enqueue(bf));}for(auto &result: results){std::cout<<"get result="<<result.get()<<"\n";}// 消息结构体作为返回值更常用std::vector<std::future<Message>> msgs;for(int i=0;i<10;i++){auto f=[](int i) { std::string m="a message from:"; m+=std::to_string(i); Message msg(i,i,i,m); return msg;};std::function<Message()> bf=std::bind(f,i);msgs.push_back(tp.enqueue(bf));}for(auto &msg: msgs){Message m(msg.get());std::cout<<"get message:"<<" from:"<<m.from<<" to:"<<m.to<<" size:"<<m.size<<" content:"<<m.content<<"\n";}return 0;
}// task task 1
// task task 3
// 2task 4// task 5
// 0task 6// task 8
// task 9
// get result=task 07// get result=1
// get result=4
// get result=9
// get result=16
// get result=25
// get result=36
// get result=49
// get result=64
// get result=81
// get message: from:0 to:0 size:16 content:a message from:0
// get message: from:1 to:1 size:16 content:a message from:1
// get message: from:2 to:2 size:16 content:a message from:2
// get message: from:3 to:3 size:16 content:a message from:3
// get message: from:4 to:4 size:16 content:a message from:4
// get message: from:5 to:5 size:16 content:a message from:5
// get message: from:6 to:6 size:16 content:a message from:6
// get message: from:7 to:7 size:16 content:a message from:7
// get message: from:8 to:8 size:16 content:a message from:8
// get message: from:9 to:9 size:16 content:a message from:9

相关文章:

C++实现一个线程池

原文链接&#xff1a;C实现一个线程池 介绍 线程池是提高CPU利用率的一个非常高效的方法,线程池就是通过预先创建多个线程,当有任务时就执行,无任务时就阻塞. 相比一般的多线程方法,线程池更加简单,模块化,并且效率更高,因为不会重复创建删除线程. 预备知识 异步线程(包括f…...

为什么inet_ntoa会返回错误的IP地址?

目录 1、调用inet_addr和inet_ntoa实现整型IP与点式字符串之间的转换 1.1、调用inet_addr将点式字符串IP转换成整型IP 1.2、调用inet_ntoa将整型IP转换成点式字符串IP 2、调用inet_ntoa返回错误点式字符串IP的原因分析 3、解决多线程调用inet_ntoa返回错误点式字符串IP的办…...

编码风格之(8)C++语言规范(Google风格)3.md

编码风格之(8)C特性规范(Google风格)3 Author: Once Day Date: 2024年10月12日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章可参考专栏: 源码分析_Once-Day的…...

openrtp 音视频时间戳问题

解决音视频发送的rtp问题 openrtp增加了音频aac的发送&#xff0c;地址 OpenRTP Gitee开源地址 同时使用两个rtp &#xff0c;来发送音频和视频 使用以下音频rtp&#xff0c;是可以发送和接收的&#xff0c;音频端口在视频端口上2 v0 o- 0 0 IN IP4 127.0.0.1 sMy Stream cI…...

了解Android中为什么需要多线程?

在Android开发中&#xff0c;多线程是一个至关重要的概念。理解并合理应用多线程&#xff0c;可以显著提升应用的性能和用户体验。 一、Android多线程的基本概念 1. 主线程与UI线程 在Android中&#xff0c;主线程也称为UI线程&#xff0c;它负责处理用户输入、事件分发、绘…...

Kaggle Python练习:使用外部库(Exercise: Working with External Libraries)

文章目录 问题1&#xff1a;坐标轴及标签显示问题2&#xff1a;赢得比赛的最佳项目并计数问题3&#xff1a;21点游戏方法1&#xff1a;把超过21点的最后记为0方法2&#xff1a;把超过21点在最后进行判断方法3&#xff1a;官方代码与方法2相似 问题1&#xff1a;坐标轴及标签显示…...

React 子组件调用父组件的方法,以及互相传递数据

<script type"text/babel" data-type"module"> import React, { StrictMode, useState } from react; import { createRoot } from react-dom/client;const ParentComponent () > {const [message, setMessage] useState("")//父组件…...

爬虫基础---python爬虫系列2

爬虫基础 文章目录 爬虫基础爬虫简介爬虫的用途爬虫的合法性规避风险看懂协议反爬机制反反爬策略 认识HTTPHTTP协议--HyperText Transfer ProtocolHTML--HyperText Markup LanguageHTTPS如何查看网站是什么协议呢使用端口号 URL组成部分详解常用的请求- Request Method常见的请…...

jmeter在beanshell中使用props.put()方法的注意事项

在jmeter中&#xff0c;通常使用beanshell去处理一些属性的设置和获取的操作&#xff0c;而这些操作也是有一定的规则的。 1. 设置属性时&#xff0c;在属性名上要加双引号&#xff0c;这代表它不是一个需要用var去声明的变量 这种设置属性的方式才是有效可行的&#xff0c;在…...

息肉检测数据集 yolov5 yolov8适用于目标检测训练已经调整为yolo格式可直接训练yolo网络

息肉检测数据集 yolov5 yolov8格式 息肉检测数据集介绍 数据集概述 名称&#xff1a;息肉检测数据集&#xff08;基于某公开的分割数据集调整&#xff09;用途&#xff1a;适用于目标检测任务&#xff0c;特别是内窥镜图像中的息肉检测格式&#xff1a;YOLO格式&#xff08;边…...

通过API进行Milvus实例配置

更新Milvus各个组件的配置参数。 调试 您可以在OpenAPI Explorer中直接运行该接口&#xff0c;免去您计算签名的困扰。运行成功后&#xff0c;OpenAPI Explorer可以自动生成SDK代码示例。 ​编辑调试 授权信息 下表是API对应的授权信息&#xff0c;可以在RAM权限策略语句的…...

Excelize 开源基础库 2.9.0 版本正式发布

Excelize 是 Go 语言编写的用于操作 Office Excel 文档基础库&#xff0c;基于 ECMA-376&#xff0c;ISO/IEC 29500 国际标准。可以使用它来读取、写入由 Excel、WPS、OpenOffice 等办公软件创建的电子表格文档。支持 XLAM / XLSM / XLSX / XLTM / XLTX 等多种文档格式&#xf…...

人脸识别-特征算法

文章目录 一、LBPH算法1.基本原理2.实现步骤3.代码实现 二、Eigenfaces算法1.特点2.代码实习 三、FisherFaces算法1.算法原理2.算法特点3.代码实现 四、总结 人脸识别特征识别器是数字信息发展中的一种生物特征识别技术&#xff0c;其核心在于通过特定的算法和技术手段&#xf…...

C++【内存管理】(超详细讲解C++内存管理以及new与delete的使用和原理)

文章目录 1.C/C内存分布2.C语言中动态内存管理方式3.C内存管理方式3.1 new/delete操作内置类型3. 2new/delete操作自定义类型 4. operator new与operator delete函数&#xff08;重点&#xff09;5. new和delete的实现原理5.1 内置类型5.2 自定义类型5.2.1 自定义类型调用new[]…...

elementUi el-table 表头高度异常问题

1、现象 在同一个页面通过状态切换不同table时&#xff0c;当从有合并标头行的table切换到无合并表头的table时&#xff0c;无合并表头的table的表头的高度异常了&#xff0c;如下图 切换后 2、解决 给每个el-table 加上一个唯一的key <el-table key"1"></…...

kubekey的应用

随着 Kubernetes 社区的不断发展&#xff0c;即将迎来 Kubernetes 1.30 版本的迭代。在早先的 1.24 版本中&#xff0c;社区作出一个重要决策&#xff1a;不再默认集成 Docker 作为容器运行时&#xff0c;即取消了对 Docker 的默认支持。这就像咱们家厨房换了个新灶头&#xff…...

如何识别并分类转录因子的家族

愿武艺晴小朋友一定得每天都开心 当我们有了差异表达的转录因子列表以后,接下来可能就想知道这些转录因子的家族分布情况是怎样的?有没有1-2个Family在其中起主要作用,占比较多。 基于这种需求,可以按以下几步来实现: 1)从AnimalTFDB4转录因子数据库中,根据需要…...

【C++11】可变模板参数详解

个人主页&#xff1a;chian-ocean 文章专栏 C 可变模板参数详解 1. 引言 C模板是现代C编程中一个非常强大且灵活的工具。在C11标准中&#xff0c;引入了可变模板参数&#xff08;variadic templates&#xff09;&#xff0c;它为模板编程带来了革命性改变。它的出现允许我们…...

本地群晖NAS安装phpMyAdmin管理MySQ数据库实战指南

文章目录 前言1. 安装MySQL2. 安装phpMyAdmin3. 修改User表4. 本地测试连接MySQL5. 安装cpolar内网穿透6. 配置MySQL公网访问地址7. 配置MySQL固定公网地址8. 配置phpMyAdmin公网地址9. 配置phpmyadmin固定公网地址 前言 本文主要介绍如何在群晖NAS安装MySQL与数据库管理软件p…...

QTableWidget 接口详情

Qt Widgets->C Classes->QTableWidget Qt 5.12版本QTableWidget接口详情&#xff08;机翻&#xff09; QTableWidget类提供了一个带有默认模型的基于项的表视图。 属性 列数columnCount : int 行数rowCount : int 细节描述 QTableWidget类提供了一个带有默认模型的基…...

k8s从入门到放弃之Ingress七层负载

k8s从入门到放弃之Ingress七层负载 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;Ingress是一个API对象&#xff0c;它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress&#xff0c;你可…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

JAVA后端开发——多租户

数据隔离是多租户系统中的核心概念&#xff0c;确保一个租户&#xff08;在这个系统中可能是一个公司或一个独立的客户&#xff09;的数据对其他租户是不可见的。在 RuoYi 框架&#xff08;您当前项目所使用的基础框架&#xff09;中&#xff0c;这通常是通过在数据表中增加一个…...

#Uniapp篇:chrome调试unapp适配

chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器&#xff1a;Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...

Yolov8 目标检测蒸馏学习记录

yolov8系列模型蒸馏基本流程&#xff0c;代码下载&#xff1a;这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中&#xff0c;**知识蒸馏&#xff08;Knowledge Distillation&#xff09;**被广泛应用&#xff0c;作为提升模型…...

PAN/FPN

import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...

Qt的学习(一)

1.什么是Qt Qt特指用来进行桌面应用开发&#xff08;电脑上写的程序&#xff09;涉及到的一套技术Qt无法开发网页前端&#xff0c;也不能开发移动应用。 客户端开发的重要任务&#xff1a;编写和用户交互的界面。一般来说和用户交互的界面&#xff0c;有两种典型风格&…...

小智AI+MCP

什么是小智AI和MCP 如果还不清楚的先看往期文章 手搓小智AI聊天机器人 MCP 深度解析&#xff1a;AI 的USB接口 如何使用小智MCP 1.刷支持mcp的小智固件 2.下载官方MCP的示例代码 Github&#xff1a;https://github.com/78/mcp-calculator 安这个步骤执行 其中MCP_ENDPOI…...

大模型——基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程

基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程 下载安装Docker Docker官网:https://www.docker.com/ 自定义Docker安装路径 Docker默认安装在C盘,大小大概2.9G,做这行最忌讳的就是安装软件全装C盘,所以我调整了下安装路径。 新建安装目录:E:\MyS…...

未授权访问事件频发,我们应当如何应对?

在当下&#xff0c;数据已成为企业和组织的核心资产&#xff0c;是推动业务发展、决策制定以及创新的关键驱动力。然而&#xff0c;未授权访问这一隐匿的安全威胁&#xff0c;正如同高悬的达摩克利斯之剑&#xff0c;时刻威胁着数据的安全&#xff0c;一旦触发&#xff0c;便可…...