[C++]基于C++11的线程池

c++11线程池实现 咳咳。c++11 加入了线程库,从此告别了标准库不支持并发的历史。然而 c++ 对于多线程的支持还是比较低级,稍微高级一点的用法都需要自己去实现,譬如线程池、信号量等。线程池(thread pool)这个东西,在面试上多次被问到,一般的回答都是:“管理一个任务队列,一个线程队列,然后每次取一个任务分配给一个线程去做,循环往复。” 貌似没有问题吧。但是写起程序来的时候就出问题了。 阅读详情

测试环境

lin@debian:~$ uname -a
Linux debian 6.1.0-23-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.99-1 (2024-07-15) x86_64 GNU/Linux

lin@debian:~$ g++ --version
g++ (Debian 12.2.0-14) 12.2.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

C++标准

-std >= c++11

参考

爱编程的大丙 -> 异步线程池(基于C++11实现)
链接:

https://subingwen.cn/cpp/threadpool/

实现

头文件

ThreadPool.h:

#ifndef INC_THREADPOOL_H
#define INC_THREADPOOL_H 1

#include <thread>
#include <functional>

namespace ThreadPool {
	int Init(const int min_threads_nums, const int max_threads_nums);
	int Destory();
	int AddTask(std::function<void()> &&task);

	template <typename Func, typename...Args>
	inline int AddTask(Func &&func, Args&&...args) {
        auto task = std::bind(std::forward<Func>(func), std::forward<Args>(args)...);
        return AddTask(std::function<void()>(std::move(task)));
	}
}
#endif

源文件

ThreadPool.cpp:

#include <map>
#include <mutex>
#include <queue>
#include <atomic>
#include <condition_variable>

#include "ThreadPool.h"

class CThreadPoolMng {
private:
	const int m_min_threads;
	const int m_max_threads;
	std::thread *m_manager;
	std::map<std::thread::id, std::thread> m_workers;
	std::vector<std::thread::id> m_ids;
	std::atomic<bool> m_stop;
	std::atomic<int> m_cur_threads;
	std::atomic<int> m_idle_threads;
	std::atomic<int> m_exit_nums;
	std::queue<std::function<void()>> m_tasks;
	std::mutex m_ids_mtx;
	std::mutex m_queue_mtx;
	std::condition_variable m_conditions;
private:
	void worker_func() {
		while (m_stop.load() != true || m_tasks.empty() != true) {
			std::function<void()> task = nullptr;
			{
				std::unique_lock<std::mutex> lock(m_queue_mtx);
				while (m_tasks.empty()) {
					m_conditions.wait(lock);
					if (m_exit_nums.load() > 0) {
						std::lock_guard<std::mutex> lck(m_ids_mtx);
						if (m_exit_nums.load() <= 0) {
							continue;
						}
						m_exit_nums--;
						m_ids.emplace_back(std::this_thread::get_id());
						std::printf("destory thread...\n");
						m_idle_threads--;
						return;
					}
					if (m_tasks.empty() && m_stop.load()) {
						std::printf("exit thread...\n");
						m_idle_threads--;
						return;
					}
				}

				if (m_tasks.empty() != true) {
					task = std::move(m_tasks.front());
					m_tasks.pop();
				}
			}
			if (task) {
				m_idle_threads--;
				task();
				m_idle_threads++;
			}
		}
	}
	void manager_func() {
		// 创建工作线程
		for (int i = 0; i < m_min_threads; i++) {
			std::thread t(&CThreadPoolMng::worker_func, this);
			m_workers.insert(std::make_pair(t.get_id(), std::move(t)));
			m_cur_threads++;
			m_idle_threads++;
		}
		while (m_stop.load() != true || m_tasks.empty() != true) {
			if (m_min_threads == m_max_threads) {
				std::this_thread::sleep_for(std::chrono::seconds(10));
				continue;
			}
			const int idle = m_idle_threads.load();													// 闲置线程
			const int current = m_cur_threads.load();												// 当前线程
			// 任务过多
			if (0 == idle && current < m_max_threads && m_tasks.empty() != true) {
				std::thread t(&CThreadPoolMng::worker_func, this);
				m_workers.insert(std::make_pair(t.get_id(), std::move(t)));
				std::printf("add thread...\n");
				m_cur_threads++;
				m_idle_threads++;
				continue;
			}
			// 线程过多
			const int delnum = ((current - m_min_threads) >= 5 ? 5 : (current - m_min_threads));	// 当线程池数过多时, 删除的线程数
			const bool more_cond = (idle > current / 2 && current - delnum >= m_min_threads);		// 线程是否过多判断条件
			if (delnum <= 0 || more_cond != true) {
				std::this_thread::sleep_for(std::chrono::seconds(1));
				continue;
			}
			m_exit_nums += delnum;
			m_conditions.notify_all();
			std::this_thread::sleep_for(std::chrono::milliseconds(10));
			std::lock_guard<std::mutex> lck(m_ids_mtx);
			for (const auto &id : m_ids) {
				auto it = m_workers.find(id);
				if (m_workers.end() == it) {
					continue;
				}
				if (it->second.joinable()) {
					it->second.join();
				}
				m_workers.erase(it);
				m_cur_threads--;
			}
			m_ids.clear();
			std::this_thread::sleep_for(std::chrono::seconds(10));
			continue;
		}

		// 销毁工作线程
		for (auto &it : m_workers) {
			std::thread &t = it.second;
			if (t.joinable()) {
				t.join();
			}
		}
	}
public:
	CThreadPoolMng(const int min_threads_nums, const int max_threads_nums) : m_min_threads(min_threads_nums), m_max_threads(max_threads_nums) {
		m_stop = false;
		m_idle_threads = m_cur_threads = m_exit_nums = 0;
		m_manager = new std::thread(&CThreadPoolMng::manager_func, this);
	}
	~CThreadPoolMng() {
		m_stop = true;
		m_conditions.notify_all();
		if (m_manager->joinable()) {
			m_manager->join();
		}
		delete m_manager;
	}
	void add_task(std::function<void()> &&task) {
		if (m_stop.load() == true) {
			return;
		}
		else {
			std::lock_guard<std::mutex> lock(m_queue_mtx);
			m_tasks.emplace(std::move(task));
		}
		m_conditions.notify_all();
	}
};

static std::mutex s_threadinit_lock;
static CThreadPoolMng *s_threadpoolmng = nullptr;

int ThreadPool::Init(const int min_threads_nums, const int max_threads_nums) {
	if (min_threads_nums < 1 || max_threads_nums < min_threads_nums) {
		return -1;
	}
	if (s_threadpoolmng != nullptr) {
		return -2;
	}
	std::lock_guard<std::mutex> lock(s_threadinit_lock);
	if (s_threadpoolmng != nullptr) {
		return -3;
	}
	s_threadpoolmng = new CThreadPoolMng(min_threads_nums, max_threads_nums);
	return 0;
}

int ThreadPool::Destory() {
	if (nullptr == s_threadpoolmng) {
		return -1;
	}
	std::lock_guard<std::mutex> lock(s_threadinit_lock);
	if (nullptr == s_threadpoolmng) {
		return -2;
	}
	delete s_threadpoolmng;
	s_threadpoolmng = nullptr;
	return 0;
}

int ThreadPool::AddTask(std::function<void()> &&task) {
	if (nullptr == s_threadpoolmng) {
		return -1;
	}
	s_threadpoolmng->add_task(std::move(task));
	return 0;
}

demo

#include <cstdio>
#include <iostream>

#include "ThreadPool.h"

void calc(const int x, const int y) {
	const int res = x + y;
	std::printf("in %s::%d:: res = [%d].\n", __func__, __LINE__, res);
	std::this_thread::sleep_for(std::chrono::seconds(10));
}

int test(const int i) {
	std::printf("in %s::%d:: i = [%d].\n", __func__, __LINE__, i);
	std::this_thread::sleep_for(std::chrono::seconds(10));
	return 0;
}

int main() {
	ThreadPool::Init(4, 100);
	for (int i = 0; i < 100; i++) {
		ThreadPool::AddTask(calc, i, i * 2);
	}
	for (int i = 0; i < 100; i++) {
		ThreadPool::AddTask(test, i);
	}
	std::getchar();             // 测试通过管理者线程检测到工作线程过多时退出工作线程
	ThreadPool::Destory();
	std::getchar();             // 测试通过delete管理者线程时退出工作线程, 一般数量为min_thread_nums
	return 0;
}
cpp11简易线程池 头文件 #include <thread> #include <mutex> #include <vector> #include <queue> #include <condition_variable> namespace base { class ThreadPool { public: static const int... 阅读详情

相关推荐

C++11 线程池demo

线程池:一种线程的使用模式,线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。 线程池工作原理: 1、主程序当前没有任务要执行,线程池中的任务队列为空闲状态.此情况下所有工作线程处于空闲的等待状态,任务缓冲队列为空. 2、主程序添加小于等于线程池中线程数量的

mac的博客 592

C++11异步线程池

【代码】C++11异步线程池。

LCZ411524的博客 742

C++11简化线程池的实现

我想用C语言写过线程池的朋友因该都知道用C语言写一个线程池有多么的麻烦,代码差不多300行左右,而且不易阅读。记得大二寒假第一次写线程池用的就是C语言,当时先参考了别人用C写的代码,说实话看起来真困难,因为C写出来的结构好乱,代码又多。我最近在实现一个自己的简单C++网络库(欢迎指点https://github.com/Miaoshuai/netlib),需要一个线程池,本来可以直接用之前拿C写的那

Shreck66的专栏 7276

C++ 11线程池

一、基本概念 1.1 为什么要用线程池 创建/销毁线程伴随着系统开销,过于频繁的创建和销毁线程会影响程序的处理效率: 如创建线程消耗时间为T1,执行任务消耗时间为T2,销毁线程消耗时间为T3,若T1+T3 > T2 ,则开启一个线程执行该任务不划算。 1.2 线程池的基本思想 因为程序边运行边创建线程是比较耗时的,所以我们通过池化的思想:在程序开始运行前创建多个线程,这样,程序在运行时,只需要从线程池中拿来用就可以了.大大提高了程序运行效率。 参考文献: https://b...

灰太狼的小秘密 8077

基于C++11封装的线程池

基于C++11封装的线程池。

FairLikeSnow的博客 276

MATLAB新手必看:SVPWM七段式算法仿真全流程解析(附完整代码)

本文为MATLAB新手和电机控制初学者提供了SVPWM七段式算法的完整仿真与代码实现指南。文章详细解析了从扇区判断、矢量作用时间计算到PWM波形生成的全流程,并附带了可直接运行的MATLAB代码,帮助读者在理解FOC控制核心算法的基础上,快速掌握工程仿真与调试技巧。

weixin_29074295的博客 281

高性能C++11线程池库 - inkooboo/thread-pool-cpp

**inkooboo/thread-pool-cpp** 是一个基于C++11标准的高性能线程池实现,旨在提供一种高效且可扩展的多线程任务执行方案。该库特别适合需要大量并发处理的任务场景,是开发高性能服务器应用和并行计算程序的理想选择。项目完全采用C++编程,并遵循MIT开源许可协议。 ## 核心功能 - **高效率工作窃取算法**:通过实施工作窃取(Work-Stealing)和工作分布平衡策

gitblog_07353的博客 631

【毕业设计参考】基于yolov8+pyqt5自适应界面设计的锂电池表面缺陷检测系统

基于YOLOv8+PyQt5的锂电池表面缺陷检测系统结合了先进的目标检测技术与友好的用户界面设计,为锂电池质量检测提供了一种高效、准确的解决方案。未来,随着深度学习技术的不断发展,我们可以进一步优化模型,提高检测精度和速度,同时拓展系统功能,如实现实时视频流检测、与生产系统的深度集成等,为锂电池产业的发展注入新的活力。希望本文对大家在相关领域的研究和实践有所帮助,欢迎大家在评论区交流讨论。

1182

C++11线程池的简单实现

c++11中添加了线程库,从此标准库有了支持并发的方案。c++11标准中的线程使用极其简单,但是c++对于多线程的支持还是比较低级,高级一点的用法都需要自己实现。 线程池原理 任务量小时,可以一个任务对应一个线程,线程资源的创建与销毁的时间消耗、上下文切换资源占用都可以忽略。但是在高并发、高吞吐、低延迟的场景下,就必须降低线程资源管理的时间消耗,就需要使用线程池了。 本文通过c++11的新特性实现一个线程池,通过管理一个任务队列、线程队列,将主线程中用户提交任务到一任务队列中,空闲的线程将从任务队列中获取任

热爱生活,忠于自己 4695

保姆级教程:将YOLOv8模型封装成Docker镜像,集成到CVAT实现自动标注

本文提供了一份详细的保姆级教程,指导如何将YOLOv8模型封装成Docker镜像并集成到CVAT平台,实现自动化标注。通过环境配置、模型服务化封装、Docker镜像构建与优化、CVAT平台集成等步骤,帮助开发者高效完成计算机视觉项目的自动标注工作流,显著提升标注效率。

weixin_28692817的博客 415

GEE:随机森林分类教程(样本制作、特征添加、训练、精度、参数优化、贡献度、统计面积)

本文将介绍在Google Earth Engine (GEE)平台上进行随机森林分类的方法和代码,其中包括制作样本点教程(本地、在线和本地在线混合制作样本点,合并样本点等),加入特征变量,运行随机森林分类器教程,计算随机森林分类结果的精度,优化随机森林分类算法的参数,打印各个变量特征的贡献度等步骤的方法和代码。本教程可以应用于多种分类场景,包括土地利用分类、种植区提取(大蒜、小麦、玉米等)、局部气候区分类、植被分类等多种场景。

养乐多的博客 1万+

C++11线程池

CPP11线程池 文章目录CPP11线程池前言要实现的组件例子源码截图源码地址 前言 C++11新添加了多线程库,但是却没有线程池,而且线程功能不完整.没有线程终止,状态判断等函数.当然C++委员会有自己的考虑.比如线程突然终止资源泄漏或内存泄漏问题.利用C++ thread实现线程池还是有一定难度的.这里参考Java的Executor和C++并发编程实战. 要实现的组件 Runnable类,可...

weixin_44048823的博客 355

新手强化学习—深入解析 YOLOv13 项目包中的文件结构和各文件作用

YOLOv13是YOLO系列最新发布的计算机视觉模型。在这篇博客中,我将深入分析YOLOv13中各个文件的作用,对整个项目的文件结构有更清晰的认识。

Limiiiing的博客 482

基于C++11 实现的线程池

C++11加入了线程库,这是历史性的一步跨越,因为它已然能够实现简单的并发了,但有这样一个问题:如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。

CltCj的博客 1558

OpenHarmony Stage模型深度解剖:从Ability Kit到沙箱隔离的全链路底层原理

基于微内核架构,提供进程管理、内存管理、IPC通信等基础能力:包含V8引擎、ArkTS运行时、渲染引擎等核心组件:Ability Kit框架,提供应用生命周期管理、组件调度等能力:基于Stage模型的应用程序。

m0_67505153的博客 191

cherry使用MCP协议Streamable HTTP实践

摘要:Streamable HTTP协议是针对传统HTTP+SSE传输方式的改进方案,解决了连接恢复、服务器资源占用和单向通信等问题。该协议基于普通HTTP实现,支持无状态服务器、纯HTTP服务和多轮对话,同时兼容现有基础设施。通过演示展示了服务端和客户端的配置方法,体现了其灵活性和实用性。MCP(多轮对话协议)作为扩展LLM能力的关键技术,代表着未来交互式AI的发展趋势。

全网120W+关注AI拉呱,专注人工智能以及科技前沿! 563

使用 C++11 实现的动态线程池项目学习

因为当线程池要关闭的时候,可能还有任务需要执行,我们最好让任务都执行完之后再关闭线程池,所以唤醒所有线程去任务队列中找任务执行;在上面的代码示例中,而且,即使作用域内部发生了异常,只要退出了作用域,就会自动解锁,避免了作用域异常导致解锁操作没有执行,从而阻塞所有线程;头文件定义的一个模板类,它封装了一个可调用对象(例如函数、lambda 表达式或函数对象),并提供了异步执行的能力。如此一来,线程不需要等待条件变量,只要任务队列中有任务,或者要销毁线程池,就立刻返回, 然后根据对应逻辑执行任务;

OutlierLi's Blog 1293

CMOS 图像传感器——Skipping 和 Binning 模式

Skipping 和 Binning 模式

沧海一升的博客 6004

基于C++11的线程池

c++11简单线程池实现(帮助理解线程池原理) 本文的源代码来自于B站up主的视频,我自己全部用了C++11的特性改写了一遍,视频链接放在最后,感觉讲的挺好的。本文的代码稍微做了一些修改,由于视频中未使用到c++11的一库,像线程库thread,互斥锁mutex,条件变量condition_variable,本案例包含3个文件,分别为threadpool.h、threadpool.cpp、main.cpp,下面给出三个文件的代码。 刚学线程池时因为有些老师说线程池是线程执行玩一个任务放回池子里,当时就不理解

qq_36831356的博客 2600

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

基于C++11实现线程池

这篇总结会将重心放在C++11的语法糖上,对于C++11的并发编程部分(等)将仅进行最简洁最必要的阐述。

lingshengxiyou的博客 941

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

基于C++11 thread 实现线程池

这里基于C++11 thread实现线程池,线程池不可拷贝。 1 nocopyable类     不可拷贝基类继承它,派生类不可拷贝,实现如下 //nocopyable.h #ifndef NOCOPYABLE_H #define NOCOPYABLE_H namespace fivestar { class nocopyable { private: nocopya

Fivestar_wang的专栏 6879

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

C++11 线程池

C++11 线程池为什么需要线程池新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 随着计算机行业的飞速发展,摩尔定律逐渐失效,多核CPU成为主流。使用多线程并行计算逐渐成为开发人员提升服务器性能的基本武器。线程池能帮助开发

qq_22611951的博客 294

[C++]C++11线程池

考虑这个场景:代码中仅在某种特殊场景(极少触发)下需要并发请求多个http链接,一方面我们不希望这些请求影响到进程的业务线程池,另一方面我们又不想单独为这个场景创建一个全局线程池使其大部分时间都在空跑。传统C++线程池仅能接受特殊的Task(执行函数需要满足特殊的格式),使用C++11特性的线程池可以更好地支持任意类型参数的Task。就是线程的一种使用模式,一个线程池中维护着多个线程等待接收管理者分配的可并发执行的任务。创建一个ThreadPool的全局变量并添加同步任务,通过。,还有一些线程池的属性。

FL1768317420的博客 846

C++11线程池实现

同样的对于消费者来说,也只需要关注缓冲区的内容,不需要关注生产者,通过异步的方式支持高并发,将一个耗时的流程拆成生产和消费两个阶段,这样生产者因为执行 put() 的时间比较短,而支持高并发。此时notify_one通知了线程池中等待的线程,通过操作系统的调度,假设唤醒了线程3,线程3拿到了资源锁,线程3就从wait状态中退出,开始工作,首先从任务队列中取出任务,并且释放资源锁(线程3从任务队列取出任务后就不需要锁了),开始执行取出的任务,如下图所示。这里创建了五个线程,用以执行分发的任务,属于。

山有木兮 1422

cpp11实现线程池(一)——项目介绍

线程池是库的形式提供给用户,是必须放到代码中,不能单独运行,亦称为基础组件第一版线程池任务对象使用继承技术,提供一个抽象基类Task,里面有一个纯虚函数run(),使用时继承该类,并重写该纯虚函数,在这个重写的纯虚函数中完成要执行的具体任务;第二版线程池使用C++11 的来包装任务执行函数,用来接受任意类型的结果。

qq_42120843的博客 1101

使用C++11相关特性实现一个线程池

本文主要用C++11的基本特性,实现了一个线程池,主要用到了std:thread,std::future,std::packaged_task,智能指针,模板等技术,可以说是把C++11涉及到的很多特性都用到了

C++ 开发者的博客 1069
上一篇: [Linux] 安装debian12后该做的事情
下一篇: [Rust] 实现SM4
scau_coderlin
博客等级 码龄3年 10粉丝 10原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值