C++多线程学习(十七、简单实现线程池)

news2024/11/15 13:52:53

目录

线程池

设计线程池的关键问题

代码

可能出现的疑问

queue> task;

总结:

template    auto InsertQueue(T&& t, Args&& ...args)->future;(t(args...))>

总结:

ThreadPool(size_t size);构造函数

总结:

templateauto ThreadPool::InsertQueue(T&& t, Args&& ...args)->future(t(args...))>

总结:


线程池

线程池是一种用于管理和控制线程的机制。它包含一个固定数量的线程组成的池子,线程池可以接收任务并分配线程来执行这些任务。线程池的主要目的是通过减少线程的创建和销毁次数,来提高线程的复用性和效率。

线程池的作用包括以下几个方面:
1. 提高性能:线程池可以避免频繁地创建和销毁线程,减少了系统开销,提高了响应速度和处理能力。
2. 提供线程管理和控制:线程池可以统一管理线程的创建、销毁和调度,可以根据任务的情况动态调整线程数目。
3. 避免资源竞争:线程池可以有效地避免多个线程同时访问共享资源导致的竞争问题,通过控制并发访问,提高了程序的稳定性和安全性。
4. 提供任务队列:线程池中的任务可以被放入任务队列中,按照先进先出的顺序执行,确保任务的顺序性和有序性。

设计线程池的关键问题

1.可使用的线程数量

2.高效的分配任务的方式

3.如何等待任务完成

 

代码

#include<iostream>
#include<thread>
#include<mutex>
#include<condition_variable>
#include<queue>
#include<functional>	//提供了函数对象和函数模板
#include<future>		//异步操作
#include<exception>		//异常用头文件
using namespace std;

class ThreadPool
{
public:
	ThreadPool(size_t size);
	~ThreadPool();
	//函数模板
	template<class T,class ...Args>
	auto InsertQueue(T&& t, Args&& ...args)->future<decltype(t(args...))>;
protected:
	queue<function<void()>> task;	//任务列表
	vector<thread> workers;			//工作线程
	
	mutex mtx_queue;
	condition_variable cv;
	bool stop;
};
//测试函数
int func(int i)
{
	printf("线程-%d-进行工作\n", i);
	//this_thread::sleep_for(1s);
	printf("线程-%d-工作结束\n", i);
	return i * i;
}


int main()
{
	ThreadPool pool(4);//创建线程池,4个线程
	vector<future<int>> result;
	for (int i = 0; i < 1000; i++)
	{
		result.emplace_back(pool.InsertQueue(func, i));
	}
	for (auto&& v:result)
	{
		printf("结果:%d\n", v.get());
	}




	return 0;
}
ThreadPool::ThreadPool(size_t size):stop(false)
{
	for (int i = 0; i < size; i++)
	{
		workers.emplace_back([this]
		{
			while (true)
			{
				function<void()> task;
				{
					unique_lock<mutex> lock(this->mtx_queue);
					this->cv.wait(lock, [this] {return this->stop || !this->task.empty(); });
					if (this->stop &&this->task.empty())
					{
						return;
					}
					task = move(this->task.front());
					this->task.pop();
				}
				task();
			}
		});
	}
}
ThreadPool::~ThreadPool()
{
	{
		unique_lock<mutex> lock(mtx_queue);
		stop = true;
	}
	cv.notify_all();
	for (auto &t :workers)
	{
		t.join();
	}
}
template<class T, class ...Args>
auto ThreadPool::InsertQueue(T&& t, Args&& ...args)->future<decltype(t(args...))>
{
	using Type = decltype(t(args...));
	auto task = make_shared<packaged_task<Type()>>(bind(forward<T>(t), forward<Args>(args)...));
	future<Type> res = task->get_future();
	{
		unique_lock<mutex> lock(mtx_queue);
		if (stop)
		{
			throw runtime_error("停止。。");
		}
		this->task.emplace([task] 
			{
				(*task)();
			});
	}
	cv.notify_one();
	return res;
}

可能出现的疑问

queue<function<void()>> task;

这是一个队列(queue),其中存储了一系列的函数对象(function),这些函数对象中的函数类型为void(),即没有参数并且无返回值的函数

这样的设计通常用于实现任务调度或异步操作。

总结:

通过将需要执行的任务(函数)依次添加到队列中,可以实现任务的顺序执行,避免了函数之间的并发访问问题。调用者可以按照自己的需求,从队列中取出函数对象并进行执行,从而实现任务的调度和执行。

template<class T,class ...Args>
    auto InsertQueue(T&& t, Args&& ...args)->future<decltype(t(args...))>;

这是一个函数模板,用于将任务插入到队列中返回一个future对象。

它有两个模板参数T和Args

T是任务的类型,它可以是一个函数指针、函数对象或lambda表达式,表示要执行的任务。

Args是可变参数模板,表示任务执行所需的参数。

函数模板的返回类型是一个auto类型,通过decltype(t(args...))来推导:这意味着返回类型将根据传入的任务类型和参数类型而定。

该函数将接受一个任务t和一系列参数args,并将它们传递给任务t进行执行。

然后,它将返回一个future对象,用于获取任务执行的结果。



总结:

使用这个函数模板,可以方便地将任务插入到队列中,并在需要时获取任务的执行结果。

ThreadPool(size_t size);构造函数

这是一个线程池的实现。首先,在构造函数中初始化一个指定大小的线程池,并使用一个布尔变量 stop 作为停止标志。然后,通过循环创建指定数量的线程,每个线程都执行一个 lambda 表达式。

lambda 表达式是一个无限循环,它首先获取线程池的锁 mtx_queue,然后等待条件变量 cv 的通知,条件线程池停止任务队列为空。如果满足条件,线程将退出循环。否则,它会从任务队列中取出一个任务并执行。

总结:

整个过程中,线程池使用互斥锁 mtx_queue 来保证多个线程对任务队列的访问是线程安全的。同时,条件变量 cv 用于在任务队列为空或线程池停止时进行通知和等待。

template<class T, class ...Args>
auto ThreadPool::InsertQueue(T&& t, Args&& ...args)->future<decltype(t(args...))>

InsertQueue 函数的目的是将一个任务添加到线程池的任务队列中,并返回一个 future 对象,用于获取任务执行的结果。

该函数使用了可变参数模板完美转发,可以接受任意类型的任务和参数。在函数内部,它首先使用 decltype 推导出任务的返回类型,并创建一个 packaged_task 对象来封装任务。

接下来,函数获取任务的 future 对象,并在一个作用域内获取任务队列的互斥锁 mtx_queue。如果线程池已经停止,函数将抛出一个运行时异常。

然后,函数使用 emplace 方法将 lambda 表达式添加到任务队列中。这个 lambda 表达式实际上是通过 bind 将任务和参数绑定,并使用 (*task)() 执行任务

最后,函数通过条件变量 cv 发送通知,告知线程池有新的任务可执行。并返回之前获取的任务结果的 future 对象。

总结:

这段代码的作用是将一个任务添加到线程池的任务队列中,并返回一个 future 对象,以便在需要时获取任务的执行结果。

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

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

相关文章

在SpringBoot中搭建微服务的项目(19版)

1.创建SpringBoot项目 2.删除不需要的,留一个pom文件 3.掉地SpringBoot的版本: <version>2.1.6.RELEASE</version> 4.导入该pom文件 <dependencies> <!-- SpringBoot启动器--><dependency><groupId>org.springframework.boot</g…

关于Redis因OAuth 2.0内存溢出解决方案

一、背景介绍 1.问题简介 本次问题是由OAuth 2.0授权框架&#xff08;用于授权第三方应用程序【客户端】访问受保护的资源。&#xff09;存储在Redis集群中的一个key引起的&#xff1a;client_id_to_access&#xff08;或称为 “client ID to access”&#xff09;通常是指在O…

安全用电管理平台针对电气火灾的解决方案 安科瑞 许敏

摘要&#xff1a; 安全用电管理平台是针对我国当前电气火灾事故频发而设计的一套电气火灾预警和预防管理系统&#xff0c;该系统是基于移动互联网、云计算技术、通过物联网传感终端&#xff08;现场监控模块、传输模块&#xff09;&#xff0c;将供电侧、用电侧电气安全参数实时…

java 打包Spring Boot项目,并运行在windows系统中

前面呢 我们已经把Spring Boot比较基础的东西都弄完了 然后呢 我们来看运维这方面的知识 首先 我们做个打包运行 其实很多人可能会比较熟悉windows系统 而linux服务器 相对没那么了解 那么我们就先来弄windows的 首先 我们要知道 为什么要打包 我们就看我们前面做的MMP项目 当…

git轻量级服务器gogs

确保本真机已启动sshd服务 sudo apt install openssh-server -y sudo systemctl start sshgogs部署 启动 sudo docker stop gogs; sudo docker rm gogs; rm -fr /build/gogs_data/*; sudo docker run --namegogs -p 10022:22 -p 10880:3000 -v /build/gogs_data:/data …

布雷默浪丹 PT 141:189691-06-3,1607799-13-2,Bremelanotide,布美诺肽

Bremelanotide&#xff0c;布雷默浪丹 PT 141&#xff0c;布美诺肽Product structure&#xff1a; Product specifications&#xff1a; 1.CAS No&#xff1a;189691-06-3/1607799-13-2 2.Molecular formula&#xff1a;C50H68N14O10 3.Molecular weight&#xff1a;1025.063 4…

抖音seo矩阵系统源码开发部署-技术开源(三)

场景&#xff1a;抖音seo源码。抖音矩阵源码&#xff0c;短视频seo源码&#xff0c;短视频矩阵源码开发部署&#xff0c;技术分享&#xff0c; 一、 抖音seo源码开发所需服务器环境配置 要开发抖音SEO矩阵系统&#xff0c;需要以下服务器环境&#xff1a; Web服务器&#xff…

Jmeter的常用设置(二)【处理乱码问题】

文章目录 前言一、察看结果树响应结果是乱码_解决方法 方法一&#xff1a;在察看结果树之前添加 后置处理器 中的 “BeanShell PostProcessor” 来动态修改结果处理编码方法二&#xff1a;在配置文件中修改二、使用步骤 1.引入库2.读入数据总结 前言 接口测试中遇到的各种问题…

使用 ViteJs 将 Jest 测试集成到现有的 Vue 3 项目中

根据我最近的经验&#xff0c;我面临着将 Jest 测试框架集成到使用Vite构建的现有Vue3 js项目中的挑战。我在各种博客上找到有用的安装指南时遇到了困难。然而&#xff0c;经过多次尝试和付出很大的努力&#xff0c;我最终找到了解决方案。在这篇博文中&#xff0c;我的目标是提…

2023黑马头条.微服务项目.跟学笔记(五)

2023黑马头条.微服务项目.跟学笔记 五 延迟任务精准发布文章1.文章定时发布2.延迟任务概述2.1 什么是延迟任务2.2 技术对比2.2.1 DelayQueue2.2.2 RabbitMQ实现延迟任务2.2.3 redis实现 3.redis实现延迟任务4.延迟任务服务实现4.1 搭建heima-leadnews-schedule模块4.2 数据库准…

Swagger简介及Springboot集成Swagger详细教程

Swagger简介及Springboot集成Swagger详细教程 学习目标 了解Swagger的作用和概念了解前后端分离在SpringBoot中集成Swagger 1、Swagger简介 前后端分离 VueSpringBoot 后端时代 前端只用管理静态页面&#xff1b;html–>后端。模版引擎JSP–>后端是主力 前后端分离式时…

获取mysql存储过程的异常信息

示例 CREATE DEFINERrootlocalhost PROCEDURE getErrorMsg() BEGIN-- 定义存储变量DECLARE code CHAR(5) DEFAULT ;DECLARE msg TEXT;DECLARE result TEXT;-- 声明异常处理DECLARE CONTINUE HANDLER FOR SQLEXCEPTIONBEGIN-- 获取异常code,异常信息GET DIAGNOSTICS CONDITION …

基于单片机的恒温恒湿温室大棚温湿度控制系统的设计与实现

功能介绍 以51单片机作为主控系统&#xff1b;液晶显示当前温湿度按键设置温湿度报警上限和下限&#xff1b;温度低于下限继电器闭合加热片进行加热&#xff1b;温度超过上限继电器闭合开启风扇进行降温湿度低于下限继电器闭合加湿器进行加湿湿度高于上限继电器闭合开启风扇进行…

干翻Dubbo系列第三篇:Dubbo术语与第一个应用程序

前言 不从恶人的计谋&#xff0c;不站罪人的道路&#xff0c;不坐亵慢人的座位&#xff0c;惟喜爱耶和华的律法&#xff0c;昼夜思想&#xff0c;这人便为有福&#xff01;他要像一棵树栽在溪水旁&#xff0c;按时候结果子&#xff0c;叶子也不枯干。凡他所做的尽都顺利。 如…

小程序页面顶部标题栏、导航栏navigationBar如何隐藏、变透明?

在app.json中的 "window"下面追加一行 "navigationStyle": "custom" 小程序顶部的白色背景条就不见了&#xff0c;直接变透明&#xff0c;只剩下右上角的胶囊按钮 警告&#xff1a; 如果页面有 <web-view src"{{src}}" /> …

机器学习实战 | MNIST手写数字分类项目(深度学习初级)

目录 简介技术流程1. 载入依赖包和数据集2. 数据预处理3. 创建卷积神经网络模型4. 训练神经网络5. 评价网络 完整程序train.py 程序gui.py程序 简介 准备写个系列博客介绍机器学习实战中的部分公开项目。首先从初级项目开始。 本文为初级项目第二篇&#xff1a;利用MNIST数据集…

111、基于51单片机的电磁感应无线充电系统 手机无线充电器设计(程序+原理图+Proteus仿真+程序流程图+论文参考资料等)

方案选择 单片机的选择 方案一&#xff1a;AT89C52是美国ATMEL公司生产的低电压&#xff0c;高性能CMOS型8位单片机&#xff0c;器件采用ATMEL公司的高密度、非易失性存储技术生产&#xff0c;兼容标准MCS-51指令系统&#xff0c;片内置通用8位中央处理器(CPU)和Flash存储单元…

在SpringBoot中对微服务项目的简单使用

准备数据库的数据 create database leq_sc; CREATE TABLE if not exists products(id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(50), #商品名称 price DOUBLE,flag VARCHAR(2), #上架状态 goods_desc VARCHAR(100), #商品描述images VARCHAR(400), #商品图?goods_stock I…

[工业互联-21]:常见EtherCAT主站方案:Kithara实时套件

第1章 Kithara实时套件概述 1.1 概述 Kithara Software是一家德国的软件公司&#xff0c;专注于实时技术和嵌入式解决方案。 他们为Windows操作系统提供了Kithara RealTime Suite&#xff0c;这是一套实时扩展模块&#xff0c;使Windows能够实现硬实时任务和控制。 Kithara…

菜比:你还不会接口测试?

很多人会谈论接口测试。到底什么是接口测试&#xff1f;如何进行接口测试&#xff1f;这篇文章会帮到你。 一、前端和后端 在谈论接口测试之前&#xff0c;让我们先明确前端和后端这两个概念。 前端是我们在网页或移动应用程序中看到的页面&#xff0c;它由 HTML 和 CSS 编写…