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

异构线程池的c++实现方案

概要

通常线程池是同质的,每个线程都可以执行任意的task(每个线程中的task顺序执行),如下图所示:

 但本文所介绍的线程和task之间有绑定关系,如A task只能跑在A thread上(因此称为异构线程池,每个线程的功能是有所区别的),如下图所示:

接口设计

TThreadPool接口设计

// 线程池
class TThreadPool
{
public:TThreadPool() {}TThreadPool(const TThreadPool&) = delete;TThreadPool& operator=(const TThreadPool& other) = delete;~TThreadPool();bool add_thread(std::string name); // add one thread into poolbool delete_thread(std::string name); // remove one thread from poolTThread* get_thread_by_name(std::string threadname); // get the thread by name, don't delete return object by yourselfbool append_task_by_thread(const std::string threadname, const std::function<void()>& task); // add task to pointed threadprivate:std::mutex m_mutex;std::map<std::string, TThread*> m_threads;
};

 TThreadPool类的主要功能是管理创建的线程(TThread,它是线程的具体实现),它提供了增加/删除线程的接口,同时给每个线程打上了标签(name)。

TThread接口设计

// 对std::thread的封装类
class TThread
{
public:TThread(std::string name);TThread(const TThread& other) = delete;TThread& operator=(const TThread& other) = delete;~TThread();bool push_task(const std::function<void()>& task); // one add taskstd::thread::id get_thread_id(); // for log purposevoid set_max_task_size(int s); // avoid thread too busyint get_task_size(); // get current task numberprivate:void work(); // real work threadvoid notify(); // notify work thread to quit
private:std::string s_name;std::atomic_bool b_running;std::thread* p_thread;std::mutex m_mutex;std::queue<std::function<void()> > m_tasks;std::condition_variable m_cond;std::atomic<int> i_maxTaskSize;
};

TThread类的主要功能是分配任务(push_task函数)和处理任务(work函数)。

代码实现

TThreadPool类

TThreadPool::~TThreadPool() {std::unique_lock<std::mutex> lk(m_mutex);for(auto iter=m_threads.begin(); iter!=m_threads.end(); iter++) {if(iter->second != nullptr) {delete iter->second;}}m_threads.clear();
}bool TThreadPool::add_thread(std::string name) {std::unique_lock<std::mutex> lk(m_mutex);if(m_threads.count(name)) {return false;}auto tt = new TThread(name);if(tt == nullptr) {return false;}m_threads[name] = tt;return true;
}bool TThreadPool::delete_thread(std::string name) {std::unique_lock<std::mutex> lk(m_mutex);if(m_threads.count(name) == 0) {return false;}delete m_threads[name];m_threads.erase(name);return true;
}TThread* TThreadPool::get_thread_by_name(std::string threadname) {std::unique_lock<std::mutex> lk(m_mutex);if(m_threads.count(threadname) == 0) {return nullptr;}return m_threads[threadname];
}bool TThreadPool::append_task_by_thread(const std::string threadname, const std::function<void()>& task)
{std::unique_lock<std::mutex> lk(m_mutex);if(m_threads.count(threadname) == 0) {return false;}auto tt = m_threads[threadname];return tt->push_task(task);
}

TThread类

const int MAX_TASK_SIZE = 100; // max task size in one threadTThread::TThread(std::string name) : s_name(name), b_running(true), i_maxTaskSize(MAX_TASK_SIZE) {p_thread = new std::thread(&TThread::work, this);
}TThread::~TThread() {notify(); // notify work thread quitif(p_thread->joinable()) {p_thread->join();}delete p_thread;
}bool TThread::push_task(const std::function<void()>& task) {std::unique_lock<std::mutex> lk(m_mutex);if(!b_running) {return false;}if(m_tasks.size() > i_maxTaskSize.load()) {return false;}m_tasks.push(task);m_cond.notify_one();return true;
}std::thread::id TThread::get_thread_id() {return p_thread->get_id();
}void TThread::set_max_task_size(int s) {if(s <= 0) {return;}i_maxTaskSize.store(s);
}void TThread::work() {std::cout << std::this_thread::get_id() << " begin work thread" << std::endl;while (b_running) { // quit even tasks remainingstd::function<void()> task;{std::unique_lock<std::mutex> lk(m_mutex);if (!m_tasks.empty()) {task = m_tasks.front();m_tasks.pop();} else if (b_running && m_tasks.empty()) {m_cond.wait(lk);}}if (task)task(); // do the task}std::cout << std::this_thread::get_id() << " end work thread"  << std::endl;
}void TThread::notify() {std::unique_lock<std::mutex> lk(m_mutex);b_running = false;m_cond.notify_one(); // mutex will be released here, therefore another thread would lock it afterward
}int TThread::get_task_size() {std::unique_lock<std::mutex> lk(m_mutex);return m_tasks.size();
}

使用方式

有两种方式可以调用对应的线程

公共代码

void func1(int i) {std::cout << "into func1: " << i << std::endl;sleep(2); // simulate real work
}TThreadPool thread_pool;thread_pool.add_thread("vdr"); // 启动vdr线程thread_pool.add_thread("xgb"); // 启动xgb线程

方式一、(先获取线程对象,然后对该线程对象添加任务)

auto tt = thread_pool.getThreadByName("vdr");
tt->push_task(std::bind(func1, 2));
tt->push_task(std::bind(func1, 5));

方式二、(直接通过线程池给对应线程添加任务)

thread_pool.append_task_by_thread("vdr", std::bind(func1, 2));
thread_pool.append_task_by_thread("vdr", std::bind(func1, 5));

注:

task是std::function<void()>类型,上面的demo是普通函数实现的,真实场景应该是类函数,实现如下:

class A {
public:void func(std::string str) {std::cout << "into A func: " << str << std::endl;}
};A a;thread_pool.append_task_by_thread("vdr", std::bind(&A::func, &a, "2"));thread_pool.append_task_by_thread("vdr", std::bind(&A::func, &a, "5"));

相关文章:

异构线程池的c++实现方案

概要 通常线程池是同质的&#xff0c;每个线程都可以执行任意的task&#xff08;每个线程中的task顺序执行&#xff09;&#xff0c;如下图所示&#xff1a; 但本文所介绍的线程和task之间有绑定关系&#xff0c;如A task只能跑在A thread上&#xff08;因此称为异构线程池&am…...

Python实现抽象工厂模式

抽象工厂模式是一种创建型设计模式&#xff0c;用于创建一系列相关或依赖对象的家族&#xff0c;而无需指定具体类。在Python中&#xff0c;可以通过类和接口的组合来实现抽象工厂模式。 下面是一个简单的Python实现抽象工厂模式的示例&#xff1a; # 抽象产品接口 class Abs…...

@vue/cli安装

vue/cli安装 1、全局安装vue/cli包2、查看是否成功 1、全局安装vue/cli包 yarn global add vue/cli2、查看是否成功 vue -V...

用友全版本任意文件上传漏洞复现

声明 本文仅用于技术交流&#xff0c;请勿用于非法用途 由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;文章作者不为此承担任何责任。 文章作者拥有对此文章的修改和解释权。如欲转载或传播此文章&#xff0c…...

程序员面试系列,MySQL常见面试题?

原文链接 一、索引相关的面试题 &#xff08;1&#xff09;索引失效的情况有哪些 在MySQL查询时&#xff0c;以下情况可能会导致索引失效&#xff0c;无法使用索引进行高效的查询&#xff1a; 数据类型不匹配&#xff1a;如果查询条件中的数据类型与索引列的数据类型不匹配&…...

前端Web实战:从零打造一个类Visio的流程图拓扑图绘图工具

前言 大家好&#xff0c;本系列从Web前端实战的角度&#xff0c;给大家分享介绍如何从零打造一个自己专属的绘图工具&#xff0c;实现流程图、拓扑图、脑图等类Visio的绘图工具。 你将收获 免费好用、专属自己的绘图工具前端项目实战学习如何从0搭建一个前端项目等基础框架项…...

2023牛客暑期多校第二场部分题解

索引 ABCDEFGHIK A 队友开的题&#xff0c;说是其实就是问能不能用若干个数异或出来某个数。 应该就是线性基板子&#xff0c;然后他写了一下就过了。 B 一开始看没什么人过不是很敢开&#xff0c;结果到后面一看题——这不是最大权闭合子图板子吗&#xff1f;&#xff1f;…...

20230724将真我Realme手机GT NEO3连接到WIN10的电脑的步骤

20230724将真我Realme手机GT NEO3连接到WIN10的电脑的步骤 2023/7/24 23:23 缘起&#xff1a;因为找使用IMX766的手机&#xff0c;找到Realme手机GT NEO3了。 同样使用IMX766的还有&#xff1a;Redmi Note12Pro 5G IMX766 旗舰影像 OIS光学防抖 OLED柔性直屏 8GB256GB时光蓝 现…...

黑马 pink h5+css3+移动端前端

网页概念 网页是网站的一页,网页有很多元素组成,包括视频图片文字视频链接等等,以.htm和.html后缀结尾,俗称html文件 HTML 超文本标记语言,描述网页语言,不是编程语言,是标记语言,有标签组成 超文本指的是不光文本,还有图片视频等等标签 常用浏览器 firefox google safari…...

Docker的七项优秀实践

众所周知&#xff0c;作为一个文本文档&#xff0c;Dockerfile包含了用户创建镜像的所有命令和说明。Docker可以通过读取Dockerfile中指令的方式&#xff0c;去自动构建镜像。因此&#xff0c;大家往往认为编写Dockerfile理应非常简单&#xff0c;只需从互联网上选择一个示例&a…...

【数据结构】24王道考研笔记——图

六、图 目录 六、图定义及基本术语图的定义有向图以及无向图简单图以及多重图度顶点-顶点间关系连通图、强连通图子图连通分量强连通分量生成树生成森林边的权、带权网/图特殊形态的图 图的存储及基本操作邻接矩阵邻接表法十字链表邻接多重表分析对比图的基本操作 图的遍历广度…...

zabbix钉钉报警

登录钉钉客户端,创建一个群,把需要收到报警信息的人员都拉到这个群内. 然后点击群右上角 的"群机器人"->"添加机器人"->"自定义", 记录该机器人的webhook值。 添加机器人 在钉钉群中&#xff0c;找到只能群助手 添加机器人 选择自定义机…...

Spring 源码解读

1、Spring 的结构组成 1.1、核心类介绍 Spring 中有两个最核心的类 1 DefaultListableBeanFactory XmlBeanFactory 继承自 DefaultListableBeanFactory&#xff0c;而DefaultListableBeanFactory 是整个 bean加载的核心部分&#xff0c;是 Spring 注册及加载 bean 的默认实现…...

练习时长两年半的网络安全防御“first”

1.网络安全常识及术语 下边基于这次攻击演示我们介绍一下网络安全的一些常识和术语。 资产 任何对组织业务具有价值的信息资产&#xff0c;包括计算机硬件、通信设施、 IT 环境、数据库、软件、文档资料、信息服务和人员等。 网络安全 网络安全是指网络系统的硬件、软件及…...

HttpRunner自动化测试之响应中文乱码处理

响应中文乱码&#xff1a; 当调用接口&#xff0c;响应正文返回的中文是乱码时&#xff0c;一般是响应正文的编码格式不为 utf-8 导致&#xff0c;此时需要根据实际的编码格式处理 示例&#xff1a; 图1中 extract 提取title标题&#xff0c;output 输出 title 变量值&#x…...

idea使用命令将jar包导入到maven仓库中

因为今天突然忘了命令&#xff0c;记下来方便以后查看 pom文件的依赖 jar包路径 进入idea中命令窗 输入命令 mvn install:install-file -DfileD:\Project\spring-cloud\dubbo-api\target\dubbo-api-1.0-SNAPSHOT.jar -DgroupIdcom.wmx -DartifactIddubbo-api -Dversion1.0…...

zookeeper学习(一) Standalone模式(单机模式)安装

安装准备 centos7环境jdk1.8环境zookeeper安装包 安装jdk 上传jdk安装包解压安装包到目录中 tar -zxvf jdk-8u361-linux-x64.tar.gz如果需要指定目录可以在后面加上 -C&#xff0c;如 tar -zxvf jdk-8u361-linux-x64.tar.gz -C 目录配置jdk环境变量 vim /etc/profile打开…...

native webrtc支持切换音频采集设备和获取裸流

https://www.yuque.com/caokunchao/rtendq/oq8w3qgs3g59whru 前言 版本webrtc m96 1、修改webrtc m96代码&#xff0c;向外提供一个adm指针的接口出来 2、外部来获取指针进行设备的选择 3、外部获取音频裸流&#xff0c;麦克风或者扬声器的数据 修改webrtc代码 1、修改H:\w…...

HR怎么看待PMP证书呢?

在当今竞争激烈的职场环境中&#xff0c;拥有专业的证书已经成为了许多人提升职业竞争力的必要途径。PMP证书作为项目管理领域的国际认证&#xff0c;备受HR和企业的青睐。那么&#xff0c;HR在招聘和评估员工时&#xff0c;究竟是如何看待PMP证书的呢&#xff1f; 首先&#x…...

API接口:如何通过使用手机归属地查询

随着手机普及率的不断增加&#xff0c;手机号码的信息查询也成为了一个非常实用的功能。本文将介绍如何通过使用手机归属地查询API接口实现查询手机号码所在地的功能。 首先&#xff0c;我们需要一个可以查询手机号码所在地的API接口。目前市面上有很多免费或付费的API接口可供…...

小创业公司死亡剧本

感觉蛮真实的&#xff1b;很多小创业公司没有阿里华为的命&#xff0c;却得了阿里华为的病。小的创业公司要想活无非以下几点&#xff1a; 1 现金流&#xff0c;现金流&#xff0c;现金流&#xff1b; 2 产品&#xff0c;找痛点&#xff0c;不要搞伪需求&#xff1b; 3 根据公司…...

国产化的接口测试、接口自动化测试工具Apipost的介绍及使用

Apipost介绍&#xff1a; Apipost是 API 文档、API 调试、API Mock、API 自动化测试一体化的研发协作赋能平台&#xff0c;它的定位 Postman Swagger Mock JMeter。 Apipost 是接口管理、开发、测试全流程集成工具&#xff0c;能支撑整个研发技术团队同平台工作&#xff0…...

【MySQL】不允许你不知道如何插入数据

&#x1f3ac; 博客主页&#xff1a;博主链接 &#x1f3a5; 本文由 M malloc 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f384; 学习专栏推荐&#xff1a;LeetCode刷题集 &#x1f3c5; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff0…...

Vue 渲染流程详解

在 Vue 里渲染一块内容&#xff0c;会有以下步骤及流程&#xff1a; 第一步&#xff0c;解析语法&#xff0c;生成AST 第二步&#xff0c;根据AST结果&#xff0c;完成data数据初始化 第三步&#xff0c;根据AST结果和DATA数据绑定情况&#xff0c;生成虚拟DOM 第四步&…...

10分钟内入门 ArcGIS Pro

本文来源&#xff1a;GIS荟 大家好&#xff0c;这篇文章大概会花费你10分钟的时间&#xff0c;带你入门 ArcGIS Pro 的使用&#xff0c;不过前提是你有 ArcMap 使用经验。 我将从工程文件组织方式、软件界面、常用功能、编辑器、制图这5个维度给大家介绍。 演示使用的 ArcGI…...

【ribbon】Ribbon的使用与原理

负载均衡介绍 负载均衡&#xff08;Load Balance&#xff09;&#xff0c;其含义就是指将负载&#xff08;工作任务&#xff09;进行平衡、分摊到多个操作单元上进行运行&#xff0c;例如FTP服务器、Web服务器、企业核心应用服务器和其它主要任务服务器等&#xff0c;从而协同…...

axios封装到reques.js文件中

封装到js中&#xff0c;避免每次都import 然后写一大堆 import axios from axios /* 可复用的发 ajax 请求的函数: axios */ let baseURLhttp://localhost:3000/ export default function promiseAjax(url,methodget,datanull,params) {return new Promise((resolve, reject) …...

学好Elasticsearch系列-核心概念

本文已收录至Github&#xff0c;推荐阅读 &#x1f449; Java随想录 文章目录 节点角色master&#xff1a;候选节点data&#xff1a;数据节点Ingest&#xff1a;预处理节点ml&#xff1a;机器学习节点remote_ cluster_ client&#xff1a;候选客户端节点transform&#xff1a;…...

扩展点都不知道不要说你用了Spring Boot

文章目录 前言1.扩展点1.1. 应用程序生命周期扩展点1.1.1 SpringApplicationRunListener1.1.2 ApplicationEnvironmentPreparedEvent1.1.3 ApplicationPreparedEvent1.1.4 ApplicationStartedEvent1.1.5 ApplicationReadyEvent1.1.6 ApplicationFailedEvent 1.2. 容器扩展点1.2…...

LangChain大型语言模型(LLM)应用开发(五):评估

LangChain是一个基于大语言模型&#xff08;如ChatGPT&#xff09;用于构建端到端语言模型应用的 Python 框架。它提供了一套工具、组件和接口&#xff0c;可简化创建由大型语言模型 (LLM) 和聊天模型提供支持的应用程序的过程。LangChain 可以轻松管理与语言模型的交互&#x…...