C++11 线程池:轻量级高并发解决方案

C++11 线程池:轻量级高并发解决方案

线程池(Thread Pool)是一种线程管理的机制,它包含了多个预先创建的线程,用于执行多个任务,这些任务被放入任务队列中等待执行。

满足我们的生产者和消费者模型。
在这里插入图片描述

线程池的核心组成部分。
  • 任务队列 -----按顺序等待要处理的任务。
  • 线程数组----- 多个已启动的线程,从任务队列拿取任务处理。
  • 互斥锁。
  • 条件变量。
  • 任务。
线程池的好处:
  • 减少线程的创建和销毁次数,提高系统的性能和效率。因为我们每次创建和销毁线程都是有开销的。
  • 活动的线程需要消耗系统资源,如果启动太多,会导致系统由于过度消耗内存或切换过度而导致系统资源不足。
  • 通过重复利用已创建的线程 ,避免了频繁创建和销毁线程的性能开销。

基于C++11实现的线程池:感受C++11的魅力

当然实际项目中的线程池可能会更复杂。但是对于初学者 ,你能够了解到这里已经足够了。

ThreadPool.h 线程池必要的接口 ,和属性。
#ifndef _THREAD_POOL_H_
#define _THREAD_POOL_H_

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <queue>
#include <functional>

class ThreadPool {
public:
	// 创建线程池单例
	static ThreadPool* getIntance(int num) {
		static ThreadPool* threadPool = nullptr;
		// call_once()   ,保证函数只能执行一次 ,只能在多线程里面使用
		std::call_once(flag_, init_threadPool, threadPool, num);
		return threadPool;
	}

	// 往线程池中添任务
	template <typename F , typename...  Agrs>
	void push_task(F &&f , Agrs&&...  agrs);

private:
	static void init_threadPool(ThreadPool*& p, int num) {
		p = new ThreadPool(num);
	}

	ThreadPool(int num = 4);   // 默认线程数是 4 
	~ThreadPool();

	std::queue<std::function<void()>>task_queue_;   // 任务队列
	std::vector<std::thread>threads;              // 线程数组
	std::mutex mutex_;   // 互斥锁
	std::condition_variable c_variable_;  // 条件变量
	bool isStop_;        // 线程池是否终止
	static std::once_flag flag_;    // call_once()  需要的flag
};

// 往任务队列添加任务
template <typename F, typename...  Agrs>
void ThreadPool::push_task(F&& f, Agrs&&...  agrs) {
	// 将函数和参数进行绑定
    // forward 实现完美转换
	std::function<void()>task = std::bind(std::forward<F>(f), std::forward<Agrs>(agrs)...);
	{
		std::unique_lock<std::mutex>lock(mutex_);
		// 加入任务队列
		task_queue_.emplace(task);
	}
	c_variable_.notify_one();   // 唤醒一个线程来执行
}

#endif // !_THREAD_POOL_H
ThreadPool.cpp 相关接口的具体实现。
#include "ThreadPool.h"

std::once_flag ThreadPool::flag_;

ThreadPool::ThreadPool(int num):isStop_ ( false ) {
	for (int i = 0; i < num ; i++) {
		
		threads.emplace_back([this]( ) {

			while ( true ) {
				std::unique_lock<std::mutex>lock(mutex_);
				c_variable_.wait(lock, [ = ]() {
					return (!task_queue_.empty() || isStop_);
					});
				if ( isStop_  && task_queue_.empty() ) {  // 如果被线程池终止了
					return;
				}
				std::cout << "线程池处理" << std::endl;

				// 从任务队列,拿出任务执行
				std::function<void( )>task(std::move(task_queue_.front()));
				task_queue_.pop();
				task();
			}
			});
	}
}

ThreadPool::~ThreadPool( ) {
	{
		std::unique_lock<std::mutex>lock(mutex_);
		isStop_ = true;
		if (!task_queue_.empty())   c_variable_.notify_all();   // 唤醒所有线程去执行任务
	}

	for ( auto& a : threads ) {
		a.join();
	}
}

测试代码:
#include "ThreadPool.h"
#include <iostream>
#include <algorithm>
#include <chrono>

void print(const char *name) {
	std::cout << "name :" << name << std::endl;
}

int getMax(int a, int b) {
	return std::max(a, b);
}

void sort(std::vector<int>*&value) {
	// 默认是升序
	std::sort(value->begin(), value->end());   // 
}

int main() {

    // 创建一个线程池 ,线程数为4
	ThreadPool *pool = ThreadPool::getIntance( 4 );
	std::vector<int>value;

	//for (int i = 1; i < 10; i++) {
	//	pool->push_task( [i]() {
	//		std::cout << "task runing " << i << std::endl;
	//		std::this_thread::sleep_for(std::chrono::seconds(1)); // 休眠1秒
	//		std::cout << "task stop : " << i << std::endl;
	//		});
	//}
	for (int i = 10; i > 0; i--) {
		value.emplace_back(i);
	}
	// 将任务投入线程池,让线程来处理
	pool->push_task(print, "小美");   // 输出小美
	pool->push_task(sort, &value);   // 升序排序
	
	std::this_thread::sleep_for(std::chrono::seconds(10)); // 休眠10秒

	for (int i = 0; i < value.size(); i++) {
		std::cout << value[i] << std::endl;
	}
	std::cout << "\n";

	return 0;
}

测试结果:

在这里插入图片描述

效果达到预期 ,当然你也可以多写几个测试案例。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java面试题:判断字符串包含字母、数字、空格、符号的数量

在Java中&#xff0c;你可以使用正则表达式来检查字符串中包含多少个字母、数字、空格和符号。也可以使用基础api来实现业务逻辑&#xff0c;方法如下&#xff1a; 1 使用Character类的静态方法 以下代码定义了一个countCharacters方法&#xff0c;它遍历字符串中的每个字符&a…

戒烟网站|基于SSM+vue的戒烟网站系统的设计与实现(源码+数据库+文档)

戒烟网站 目录 基于SSM&#xff0b;vue的戒烟网站系统的设计与实现 一、前言 二、系统设计 三、系统功能设计 1网站功能模块 2管理员功能模块 3用户功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主…

REACT 在组件之间共享状态

有时&#xff0c;您希望两个组件的状态始终一起变化。要做到这一点&#xff0c;请从他们俩身上删除状态&#xff0c;将其移动到他们最近的共同父级&#xff0c;然后通过道具将其传递给他们。这被称为提升状态&#xff0c;这是编写 React 代码时最常见的事情之一。 举例提升状态…

从ROS到数据库:用Python将ROS话题消息保存到数据库

观前提醒&#xff1a;本博客介绍如何使用Python订阅ROS话题,并将接收到的消息保存到SQL数据库中,包括MySQL和SQL Server两种情况。 使用Python订阅ROS话题并将消息保存至MySQL数据库 下面我们将详细介绍如何使用Python订阅ROS话题&#xff0c;并将接收的数据保存到MySQL数据库…

Postman基础功能-Collection集合和批量运行

一、Collection&#xff08;集合&#xff09;介绍 当我们对一个或多个系统中的很多接口用例进行维护时&#xff0c;首先想到的就是对接口用例进行分类管理&#xff0c;同时还希望对这批接口用例做回归测试。 在 Postman 中也提供了这样一个功能&#xff0c;就是 Collec…

【网站项目】SpringBoot781乐乐农产品销售系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

上官婉儿传奇的一生(戴罪之身入宫,却深得两任君主重用)

她最初的身份是罪臣之女、官婢&#xff0c;历经三代帝王更迭&#xff0c;她顶着后妃的头衔&#xff0c;成为武则天和李显的内阁大总管&#xff0c;她是如何赢得两位帝王的信任&#xff1f; 01从官婢到女官的逆袭 公元664年&#xff0c;上官婉儿出生在唐高宗时代&#xff0c;她…

免费无限换脸 - 最强AI换脸Facefusion整合包最新版来啦!

今天我要分享的是FaceFusion最新版&#xff0c;它最近更新到了2.5.3版本&#xff0c;带来了许多激动人心的改进和优化。 Facefusion2.5.3版本介绍 FaceFusion不仅仅是一款换脸软件&#xff0c;它更是一个多功能的数字人和实时直播助手&#xff0c;真正开启了个性化媒体的新时代…

tomcat 的启动流程

tomcat 的启动流程 中 使用的Lifecycle 生命流程 。在这里还使用了设计模式中的模板模式&#xff08;LifecycleBase 是一个模板类&#xff09; init&#xff08;&#xff09;方法 start() 方法 container 的处理

【STM32 |示例程序】EXTI中断示例程序(对射式红外传感器旋转编码器计次)

✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天开心哦&#xff01;✨✨ &#x1f388;&#x1f388;作者主页&#xff1a; 丠丠64-CSDN博客&#x1f388;&#x1f388; ✨✨ 帅哥美女们&#xff0c;我们共同加油&#xff01;一起…

携程网站_广州动物园景点评论采集和处理

一、爬取携程网站_广州动物园景点评论数据100条 数据包括&#xff1a;用户名、评论文本内容、发布时间</n> 结果分别保存在userNames&#xff0c;commentDetails commentTimes列表中。 import requests import json import time userNames [] commentDetails [] com…

ComfyUI相见恨晚的提示词插件,简直堪称神器!

之前我曾介绍过一款专为SD设计的中文提示词插件——prompt-all-in-one&#xff0c;想必使用过的小伙伴们都已经感受到了它的便捷与实用吧。 不过&#xff0c;那款插件是基于webUI版本的&#xff0c;而现在&#xff0c;越来越多的朋友开始探索ComfyUI这一新选择。 假如在Comfy…

Netty-面试题(中)(五十)

关于零拷贝和堆外内存 Java在将数据发送出去的时候&#xff0c;会先将数据从堆内存拷贝到堆外内存&#xff0c;然后才会将堆外内存再拷贝到内核态&#xff0c;进行消息的收发&#xff0c;代码如下: 所以&#xff0c;我们发现&#xff0c;假如我们在收发报文的时候使用直接内存&…

(接上一篇linux rocky 搭建DNS高阶版)实现不同网段访问解析不同的服务器并加域

上一篇链接&#xff1a;linux rocky 搭建DNS服务和禁止AD域控DNS&#xff0c;做到独立DNS并加域-CSDN博客文章浏览阅读417次&#xff0c;点赞13次&#xff0c;收藏7次。使用linux rocky 搭建DNS服务&#xff0c;用于独立AD域控DNS存在&#xff0c;并且实现加域。https://blog.c…

从需求到实现:能源软件服务商如何量身定制企业解决方案

能源行业需要数字化转型的原因主要有以下几点&#xff1a;首先&#xff0c;数字化技术可以提高生产效率和安全性&#xff0c;通过实时监控和智能调度降低事故风险&#xff0c;并实现远程控制和自动化生产。其次&#xff0c;数字化转型有助于推动能源行业的创新发展&#xff0c;…

51单片机GPS+sim800c GSM定位短信LCD1602液晶显示 原理图+PCB+源码

目录 1、实物图 2、原理图 ​3、PCB​编辑 4、程序 资料下载地址&#xff1a;51单片机GPSsim800c GSM定位短信LCD1602液晶显示 原理图PCB源码 1、实物图 2、原理图 3、PCB 4、程序 #include "common.h" #include "uart.h" #include "gps.h&…

Linux(多线程)

//blockQueue.hpp #pragma once #include <iostream> #include <queue> #include <pthread.h> const int gcap 5; template <class T> class BlockQueue { public:BlockQueue(const int cap gcap):_cap(cap)//初始化阻塞队列的容量{pthread_mutex_in…

java发送请求-二次开发-get请求json

这里有2个判断 如果param为空则对url发送请求 再继续判断有值时&#xff0c;接口参数时json还是namevalue格式 因为json是带{,所以可以先写为param包含{}, 反之就是请求格式是url&#xff1f;param 请求json要带参数&#xff0c;所以需要使用setEntity方法&#xff0c; 最…

数字人解决方案——AniTalker声音驱动肖像生成生动多样的头部说话视频算法解析

1.概述 AniTalker是一款先进的AI驱动的动画生成工具&#xff0c;它超越了简单的嘴唇同步技术&#xff0c;能够精准捕捉并再现人物的面部表情、头部动作以及其他非言语的微妙动态。这不仅意味着AniTalker能够生成嘴型精准同步的视频&#xff0c;更重要的是&#xff0c;它还能够…

Mongo关联查询两张表中分别满足某些条件的记录

如果是在mysql里面&#xff0c;这个查起来就很方便&#xff0c;但是&#xff0c;在mongo里面的话&#xff0c;查询起来就没这么方便了。 如果使用付费版的Studio 3T工具的话&#xff0c;也可以像使用mysql一样查询mongo数据&#xff0c;但是免费版不支持sql的用法&#xff0c;只…