手写能任务窃取的线程池

目录

function_wrapper.hpp:

stealing_queue.hpp

thread_pool_steal_hpp

参考:《C++并发编程实战》

对于thread_pool_steal.hpp的代码有改动,不然运行不了

function_wrapper.hpp:


//包装可调用对象,对外消除对象型别,还需要有一个函数调用符
//
//
//私有成员:
//      1.一个虚基类(没有的话在3很难定义一个指向实例化类的指针)
//      struct impl_base{
//              1.一个纯虚函数用来让派生类继承3执行函数
//              2.虚析构函数
//      }
//      2.因为需要接受任意类型的可调用对象,所以内部需要封装一个模板类(派生自1>)
//      template<typename F>
//      struct impl_type{
//              1.成员变量:传入的函数
//              2.构造函数:移动构造成员变量
//              3.成员函数:执行函数
//      }
//      3.一个指向实例化后的指针(在这里看出确实需要一个基类,可以通过基类指针构
造派生类指针)
//公有成员:
//      1.构造函数,因为接收的对象是任意类型,所以是模板构造函数,并且使用万能引
用和完美转发实例化私有成员的3.
//      2.()运算符的重载通过调用私有成员2.的3.实现
//      3.默认构造函数 = default
//      4.移动拷贝构造函数
//      5.移动复制构造函数
//   
 

#ifndef _FUNCTION_WRAPPER_HPP_
#define _FUNCTION_WRAPPER_HPP_#include<memory>
class function_wrapper
{struct impl_base{virtual void call() = 0;virtual ~impl_base(){};};	template<typename Function>struct impl_type:impl_base{Function f;impl_type(Function&& f_):f(std::move(f_)){}void call(){ f(); }};std::unique_ptr<impl_base> impl;
public:function_wrapper() = default;template<typename Function>function_wrapper(Function&& f):impl(new impl_type<Function>(std::move(f)))	{}void operator()(){impl->call();}function_wrapper(function_wrapper&& other):impl(std::move(other.impl)) {}function_wrapper& operator=(function_wrapper&& other){impl = std::move(other.impl);return *this;}function_wrapper(function_wrapper& other) = delete;function_wrapper(const function_wrapper& other) = delete;function_wrapper& operator=(const function_wrapper& other)=delete;};
#endif

stealing_queue.hpp


//可以进行任务窃取的队列
//
//私有成员:
//      1.一个双端队列,pop操作在队头进行,steal操作在队尾进行,存储的内容为function_wrapper类
//      2.互斥 保证安全,因为不存储线程,所以不需要条件变量传递线程运行信息
//公有成员:
//      1.默认构造函数
//      2.push
//      3.try_pop
//      4.try_steal基本和pop都一样,就是弹出队尾元素//在线程池中定义一个存储窃取
队列的vector,vector的索引代表每个线程的标识,这样每个线程就可以通过这个vector访>问窃取队列。
//      5.empty
 

#ifndef _STEALING_QUEUE_HPP
#define _STEALING_QUEUE_HPP#include"function_wrapper.hpp"
#include<deque>
#include<mutex>
class work_stealing_queue
{typedef function_wrapper data_type;std::deque<data_type> the_queue;mutable std::mutex mut;
public:work_stealing_queue(){}work_stealing_queue(const work_stealing_queue& othre) = delete;work_stealing_queue& operator=(const work_stealing_queue& othre) = delete;void push(data_type data){std::lock_guard<std::mutex> lk(mut);the_queue.push_front(std::move(data));}bool try_pop(data_type& data){std::lock_guard<std::mutex> lk(mut);if(the_queue.empty())return false;else{data = std::move(the_queue.front());the_queue.pop_front();return true;}}bool try_steal(data_type& data){std::lock_guard<std::mutex> lk(mut);if(the_queue.empty())return false;else{data = std::move(the_queue.front());the_queue.pop_back();return true;}}bool empty() const{std::lock_guard<std::mutex> lk(mut);return the_queue.empty();}
};#endif

thread_pool_steal_hpp:

//私有成员:
//      1.控制线程正常运行的原子变量,抛出异常设置为true
//      2.线程池的池队列,基于普通的线程安全队列
//      3.提供索引的队列存储指向窃取队列的指针
//      4.存放线程的队列
//      5.封装可联结线程
//      6.静态本地线程变量 本地线程队列
//      7.静态本地线程变量 索引
//
//      8.work_thread工作函数(任务函数)
//      9.判断能否从 本地线程队列获取任务
//      10.判断能否从 线程池队列获取任务
//      11.判断能否从 其他线程窃取任务
//公有成员:
//      1.构造函数:初始化原子变量,可联结线程类。
//      {
//              try
//              {       
//                      for()
//                      {初始化提供索引的队列   }
//                      for()
//                      {初始化线程}
//              }
//              catch
//      }
//      2.提交任务函数//为了获取返回值应该返回future,传入各种函数,所以应该是模
板函数{
//              1.传入函数打包给pakage_task
//              2.获取future
//              3.判断是传入本地线程队列还是线程池队列
//              4.return future;
//      }
//      3.run_package_task//work_thread的主要部分
//      {
//              if(判断从哪个队列获得任务)
//              {
//                      task()
//              }
//              else 交出cpu时间。
//        }

//        4.析构函数
 

#ifndef _THREAD_POOL_STEAL_HPP_
#define _THREAD_POOL_STEAL_HPP_#include "threadsafe_queue.hpp"
#include "ThreadRAII.h"
#include "stealing_queue.hpp"
#include "function_wrapper.hpp"
#include "stealing_queue.hpp"#include<atomic>
#include<vector>
#include<memory>
#include<thread>
#include<future>
class thread_pool_steal
{typedef function_wrapper task_type;std::atomic_bool done;threadsafe_queue<task_type> pool_work_queue;std::vector<std::unique_ptr<work_stealing_queue>> queues;std::vector<std::thread> threads;join_threads joiner;static thread_local work_stealing_queue* local_work_queue;static thread_local unsigned my_index ;void work_thread(unsigned index){my_index = index;local_work_queue = queues[my_index].get();while(!done){run_pending_task();}	}bool pop_from_local(task_type& task){return local_work_queue && local_work_queue->try_pop(task);}bool pop_from_pool(task_type& task){return pool_work_queue.try_pop(task);}bool pop_from_steal(task_type& task){work_stealing_queue steal_queue;for(unsigned i = 0; i<queues.size(); i++){unsigned index =(my_index + i+1)%queues.size();if(queues[index]->try_steal(task)){return true;}}return false;}
public:thread_pool_steal():done(false),joiner(threads){unsigned number = std::thread::hardware_concurrency();try{for(unsigned i = 0; i<number ;i++){queues.push_back(std::unique_ptr<work_stealing_queue>(new work_stealing_queue));}for(unsigned i = 0; i<number; i++){threads.push_back(std::thread(&thread_pool_steal::work_thread,this,i));}}catch(...){done = true;throw;}}~thread_pool_steal(){done = true;}template <typename Function>std::future<typename std::result_of<Function()>::type> submit(Function f){typedef typename std::result_of<Function()>::type result_type;std::packaged_task<result_type()> task(f);std::future<result_type> res(task.get_future());int index = 0;for(auto& ptr:queues){if(ptr->empty()){ptr->push(std::move(task));index = -1;break;}index++;}if(index>=0){pool_work_queue.push(std::move(task));}return res;}void run_pending_task(){task_type task;if(pop_from_local(task) || pop_from_pool(task) || pop_from_steal(task)){task();}else{std::this_thread::yield();}}};
thread_local work_stealing_queue* thread_pool_steal::local_work_queue = nullptr;
thread_local unsigned thread_pool_steal::my_index = 0;
#endif

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

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

相关文章

线性表相关知识

1.简述 线性表&#xff0c;全名为线性存储结构。使用线性表存储数据的方式可以这样理解&#xff0c;即“把所有数据按照顺序&#xff08;线性&#xff09;的存储结构方式&#xff0c;存储在物理空间”。 按照空间分类&#xff1a; 顺序存储结构&#xff1a;数据依次存储在连续…

【Zookeeper专题】Zookeeper经典应用场景实战(一)

目录 前置知识课程内容一、Zookeeper Java客户端实战1.1 Zookeeper 原生Java客户端使用1.2 Curator开源客户端使用快速开始使用示例 二、Zookeeper在分布式命名服务中的实战2.1 分布式API目录2.2 分布式节点的命名2.3 分布式的ID生成器 三、zookeeper实现分布式队列3.1 设计思路…

screen命令

screen命令 安装screen状态介绍帮助查询查看已经存在的screen终端创建一个叫liu的虚拟终端回到主终端回到虚拟终端清除终端 安装screen # CentOS yum install screen # Debian/Ubuntu apt install screen状态介绍 Attached&#xff1a;表示当前screen正在作为主终端使用&…

完美解决 flex 实现一行三个,显示多行,左对齐

效果图 代码 <body><section class"content"><div class"item">元素</div><div class"item">元素</div><div class"item">元素</div><div class"item">元素</di…

代理IP与Socks5代理的技术奇妙之旅

随着数字化时代的崛起&#xff0c;网络工程师们日益承担着维护网络稳定性和保护数据安全的重任。在这个充满挑战的世界里&#xff0c;代理IP与Socks5代理技术成为了他们的秘密武器&#xff0c;本文将带您踏上一段技术奇妙之旅&#xff0c;深入了解这两项技术在不同领域中的应用…

【MySQL】Linux 中 MySQL 环境的安装与卸载

文章目录 Linux 中 MySQL 环境的卸载Linux 中 MySQL 环境的安装 Linux 中 MySQL 环境的卸载 在安装 MySQL 前&#xff0c;我们需要先将系统中以前的环境给卸载掉。 1、查看以前系统中安装的 MySQL rpm -qa | grep mysql2、卸载这些 MySQL rpm -qa | grep mysql | args yum …

关于Jupyter markdown的使用

一级标题 #空格 标题1 二级标题 ## 空格 标题2 三级标题 ###空格 标题3 无序&#xff1b; 有序&#xff1a; 数学符号&#xff1a;

链表的基本操作(数据结构)

单链表 #include <stdlib.h> #include <iostream> #include <stdio.h> typedef struct LNode{int data;struct LNode *next; }LNode,*LinkList;打印链表 void PrintList(LNode *p) {LNode *temp;temp p->next;printf("链表的顺序:");while(t…

Rust Http 性能测试框架/工具

在Rust中&#xff0c;有几个常用的性能测试框架和工具可用于对HTTP性能进行测试。以下是其中一些&#xff1a; 1、Criterion&#xff1a;Criterion是一个通用的性能测试框架&#xff0c;可以用于测试各种类型的代码性能&#xff0c;包括HTTP性能。你可以使用Criterion来编写和运…

使用UiPath和AA构建的解决方案 3. CRM 自动化

您是否曾经从一个应用程序中查找数据并更新另一个系统? 在许多情况下,人们在系统之间复制和移动数据。有时,可能会发生“转椅活动”,从而导致人为失误。RPA可以帮助我们自动化这些活动,使其更快,同时还可以消除任何人为错误。 在这个项目中,我们将在客户服务中自动化一…

正则验证用户名和跨域postmessage

一、正则验证用户名 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>登录</title> </head> <body> <form action"/login" method"post"><input type…

系统架构设计:3 软件架构建模技术与应用

目录 一 架构“4+1”视图 二 论点 1 架构的本质 2 “4+1”视图 (1)逻辑视图 <

蓝桥杯每日一题2023.10.2

时间显示 - 蓝桥云课 (lanqiao.cn) 题目描述 题目分析 输入为毫秒&#xff0c;故我们可以先将毫秒转化为秒&#xff0c;由于只需要输出时分&#xff0c;我们只需要将天数去除即可&#xff0c;可以在这里多训练一次天数判断 #include<bits/stdc.h> using namespace std…

【网络安全 --- kali2023安装】超详细的kali2023安装教程(提供镜像资源)

如果你还没有安装vmware 虚拟机&#xff0c;请参考下面博客安装 【网络安全 --- 工具安装】VMware 16.0 详细安装过程&#xff08;提供资源&#xff09;-CSDN博客【网络安全 --- 工具安装】VMware 16.0 详细安装过程&#xff08;提供资源&#xff09;https://blog.csdn.net/m0…

python代码封装二进制文件并使用C#调用方案

思路 首先使用Cython库将python代码生成二进制文件pyd&#xff0c;然后使用C#中的pythonnet的Nuget包来进行调用&#xff0c;python代码中可以使用第三方类库。 Cython使用 Cython的安装 在命令行中使用如下语句即可安装Cython pip install cythonpyd文件格式 Cython用于…

openGauss学习笔记-93 openGauss 数据库管理-访问外部数据库-oracle_fdw

文章目录 openGauss学习笔记-93 openGauss 数据库管理-访问外部数据库-oracle_fdw93.1 编译oracle_fdw93.2 使用oracle_fdw93.3 常见问题93.4 注意事项 openGauss学习笔记-93 openGauss 数据库管理-访问外部数据库-oracle_fdw openGauss的fdw实现的功能是各个openGauss数据库及…

Umijs介绍

今天我们来看 umijs 我们访问官网 https://umijs.org/ 这是一个可 插拔的企业级 React框架 当然 你也可以选择 React 的一个脚手架 但是 这样就有很多需要考虑的东西 用这个umi 很多点 我们就不需要考虑了 框架已经帮我们配置好了 这边 我们点击快速上手的一个 指南 我们可…

非 Prop 的属性

概念 父组件传给子组件的属性&#xff0c;但该属性没有在子组件 props 属性里定义。 属性继承 非 Prop 的属性默认情况下会被子组件的根节点继承&#xff0c;非 prop 的属性会保存在子组件 $attrs 属性里。 举例 子组件 date-picker 如下 <!-- 我是子组件 date-picker --&…

数据结构刷题训练——二叉树篇(一)

&#x1f4d9;作者简介&#xff1a; 清水加冰&#xff0c;目前大二在读&#xff0c;正在学习C/C、Python、操作系统、数据库等。 &#x1f4d8;相关专栏&#xff1a;C语言初阶、C语言进阶、C语言刷题训练营、数据结构刷题训练营、有感兴趣的可以看一看。 欢迎点赞 &#x1f44d…

贪心找性质+dp表示+矩阵表示+线段树维护:CF573D

比较套路的题目 首先肯定贪心一波&#xff0c;两个都排序后尽量相连。我一开始猜最多跨1&#xff0c;但其实最多跨2&#xff0c;考虑3个人的情况&#xff1a; 我们发现第3个人没了&#xff0c;所以可以出现跨2的情况 然后直接上dp&#xff0c;由 i − 1 , i − 2 , i − 3 i…