C++多线程编程——基于策略模式、单例模式和简单工厂模式的可扩展智能析构线程

1. thread对象的析构问题

在 C++ 多线程标准库中,创建 thread 对象后,必须在对象析构前决定是 detach 还是 join。若在 thread 对象销毁时仍未做出决策,程序将会终止。

然而,在创建 thread 对象后、调用 join 前的代码中,若程序抛出异常,就会跳过 join 的调用,进而导致程序终止。

因此,必须在异常捕获中也调用 join。

这无疑增加了编程的复杂性,因为每个相关位置都需要在正常流程中写一次 join,在异常捕获中再写一次。

下面的代码将演示这一情况:

#include <iostream>
#include <thread>using namespace std;void threadFunc()
{cout << "Hello from thread" << endl;
}int main()
{thread t(threadFunc);try{throw runtime_error("Something went wrong");}catch (...){t.join();throw;}t.join();
}

2. 一种简单的解决办法——RAII

一种简单的解决办法就是使用RAII思想,编写一个类来绑定一个thread对象,在类的析构函数中调用thread对象的join方法。

下面的代码展示了这一点:

#include <iostream>
#include <thread>using namespace std;class thread_guard
{
public:thread_guard(std::thread& t) : t_(t) {}~thread_guard(){if (t_.joinable()){t_.join();}}thread_guard(const thread_guard&) = delete;thread_guard& operator=(const thread_guard&) = delete;
private:thread& t_;
};void threadFunc()
{cout << "Thread function running..." << endl;
}int main()
{thread t(threadFunc);thread_guard g(t);return 0;
}

局部对象会自动被销毁,在销毁时thread_guard类对象的析构函数会自动调用thread类对象的join方法,从而保证thread不会异常终止。

但是这种方法太死板了,只会调用join方法。

我们可能希望自己选择detach或者join,也可能想要在thread对象销毁时做一些别的事情。

出于这种想法,本文提出了一种可扩展的智能析构线程,下面将对其进行介绍。

3. 可扩展的智能析构线程

首先,对于thread对象析构时不同的处理,这里使用了策略模式。通过提供不同的策略类,就可以扩展出不同的析构行为。

同时,目前实现的策略类没有自己的成员函数,所以采用了单例模式来创建,避免创建出大量相同的对象而造成内存浪费。

最后,通过简单工厂模式来获取策略类。

下面展示一下具体的代码:

#include <iostream>
#include <thread>using namespace std;class thread_destroy_strategy
{
public:virtual void destroy(thread& t)const = 0;virtual ~thread_destroy_strategy() = default;
};class join_strategy : public thread_destroy_strategy
{
public:static join_strategy* getInstance(){static join_strategy instance;return &instance;}void destroy(thread& t)const override{if (t.joinable()){t.join();cout << "Thread " << this_thread::get_id() << " joined" << endl;}}
};class detach_strategy : public thread_destroy_strategy
{
public:static detach_strategy* getInstance(){static detach_strategy instance;return &instance;}void destroy(thread& t)const override{if (t.joinable()){t.detach();cout << "Thread " << this_thread::get_id() << " detached" << endl;}}
};enum class EThreadStrategy
{JOIN,DETACH
};class strategyFactory
{
public:static thread_destroy_strategy* getStrategy(EThreadStrategy strategy){switch (strategy){case EThreadStrategy::JOIN:return join_strategy::getInstance();case EThreadStrategy::DETACH:return detach_strategy::getInstance();default:return nullptr;}}
};class auto_thread
{
public:template<typename F, typename... Args>auto_thread(F&& f, Args&&... args) : t(forward<F>(f), forward<Args>(args)...) {}~auto_thread(){thread_destroy_strategy* pStrategy = strategyFactory::getStrategy(strategy);if (pStrategy){pStrategy->destroy(t);}}auto_thread(const auto_thread&) = delete;auto_thread& operator=(const auto_thread&) = delete;public:void setStrategy(EThreadStrategy strategy_){strategy = strategy_;}
private:thread t;EThreadStrategy strategy = EThreadStrategy::JOIN;
};void threadFunc()
{cout << "Hello from thread" << endl;
}int main()
{auto_thread t(threadFunc);t.setStrategy(EThreadStrategy::JOIN); // 默认就是JOIN策略, 也可以设置为DETACH策略
}

策略类在destroy时打印了一下线程id。

运行结果如下图所示:

以上就是本文的全部内容

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

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

相关文章

LeetCode 0922.按奇偶排序数组 II:O(1)空间复杂度-一次遍历双指针

【LetMeFly】922.按奇偶排序数组 II&#xff1a;O(1)空间复杂度-一次遍历双指针 力扣题目链接&#xff1a;https://leetcode.cn/problems/sort-array-by-parity-ii/ 给定一个非负整数数组 nums&#xff0c; nums 中一半整数是 奇数 &#xff0c;一半整数是 偶数 。 对数组进…

UE求职Demo开发日志#21 背包-仓库-装备栏移动物品

1 创建一个枚举记录来源位置 UENUM(BlueprintType) enum class EMyItemLocation : uint8 {None0,Bag UMETA(DisplayName "Bag"),Armed UMETA(DisplayName "Armed"),WareHouse UMETA(DisplayName "WareHouse"), }; 2 创建一个BagPad和WarePa…

SQLModel入门

目录 概述快速开始官方教程简单使用样例 概述 SQLModel 是一个 ORM 框架&#xff0c;其基于 SQLAlchemy 和 Pydantic&#xff0c;其中 SQLALchemy 提供底层 ORM 能力&#xff0c;Pydantic 提供类型校验能力&#xff0c;SQLModel 中&#xff0c;一个 SQLModel model 既是一个 S…

分割链表

题目&#xff1a; 给定一个链表的头节点和一个特定值 x &#xff0c;请你对链表进行分隔&#xff0c;使得所有小于 x 的节点都出现在大于等于 x 的节点之前 ( 链表中节点数为[0,500]&#xff0c;不要求链表的顺序 &#xff09; 思路一&#xff1a;在原链表上进行修改 在原链表…

DeepSeek-R1:开源机器人智能控制系统的革命性突破

目录 引言 一、DeepSeek-R1 的概述 1.1 什么是 DeepSeek-R1&#xff1f; 1.2 DeepSeek-R1 的定位 二、DeepSeek-R1 的核心特性 2.1 实时控制能力 2.2 多传感器融合 2.3 路径规划与导航 2.4 人工智能集成 2.5 开源与模块化设计 2.6 跨平台支持 三、DeepSeek-R1 的技术…

starrocks最佳实践、行业实践

最佳实践 starrocks最佳实践 最佳实践集合 Bitmap索引适用场景和最佳实践 行业实践 行业实践

响应式编程_01基本概念:前世今生

文章目录 引言响应式编程的技术优势全栈式响应式编程从传统开发模式到异步执行技术Web 请求与 I/O 模型异步调用的实现技术回调Future机制 响应式编程实现方法观察者模式发布-订阅模式数据流与响应式 响应式宣言和响应式系统 引言 大流量、高并发的访问请求的项目&#xff0c;…

一文速览DeepSeek-R1的本地部署——可联网、可实现本地知识库问答:包括671B满血版和各个蒸馏版的部署

前言 自从deepseek R1发布之后「详见《一文速览DeepSeek R1&#xff1a;如何通过纯RL训练大模型的推理能力以比肩甚至超越OpenAI o1(含Kimi K1.5的解读)》」&#xff0c;deepseek便爆火 爆火以后便应了“人红是非多”那句话&#xff0c;不但遭受各种大规模攻击&#xff0c;即便…

Vue.js 使用组件库构建 UI

Vue.js 使用组件库构建 UI 在 Vue.js 项目中&#xff0c;构建漂亮又高效的用户界面&#xff08;UI&#xff09;是很重要的一环。组件库就是你开发 UI 的好帮手&#xff0c;它可以大大提高开发效率&#xff0c;减少重复工作&#xff0c;还能让你的项目更具一致性和专业感。今天…

队列 + 宽搜(4题)

目录 1.n叉树的层序遍历 2.二叉树的锯齿形层序遍历 3.二叉树的最大宽度 4.在每个树行中找最大值 1.n叉树的层序遍历 429. N 叉树的层序遍历 - 力扣&#xff08;LeetCode&#xff09; 我们只需要把某个节点出队的时候把它的孩子节点添加进来即可。 出队的次数就是最开始队列…

计算机基础知识(第二篇)

计算机基础知识&#xff08;第二篇&#xff09; 嵌入式技术 嵌入式技术 特点&#xff1a;专用性、实时性、低成本、可靠性、体积小 应用&#xff1a;汽车电子、家用电器、通信设备、安防监控、工业自动化、医疗设备 体系结构&#xff1a; 冯诺依曼结构&#xff1a;传统计…

HTML 标题

HTML 标题 引言 HTML&#xff08;超文本标记语言&#xff09;是构建网页的基础&#xff0c;而标题则是网页中不可或缺的元素。标题不仅能够帮助用户快速了解网页内容&#xff0c;还能够对搜索引擎优化&#xff08;SEO&#xff09;产生重要影响。本文将详细介绍HTML标题的用法…

惰性函数【Ⅱ】《事件绑定的自我修养:从青铜到王者的进化之路》

【Ⅱ】《事件绑定的自我修养&#xff1a;从青铜到王者的进化之路》 1. 代码功能大白话&#xff08;给室友讲明白版&#xff09; // 青铜写法&#xff1a;每次都要问浏览器"你行不行&#xff1f;" function addEvent青铜版(element, type, handler) {if (window.add…

sentinel的限流原理

Sentinel 的限流原理基于 流量统计 和 流量控制策略&#xff0c;通过动态规则对系统资源进行保护。其核心设计包括以下几个关键点&#xff1a; 流量统计模型&#xff1a;滑动时间窗口 Sentinel 使用 滑动时间窗口算法 统计单位时间内的请求量&#xff0c;相比传统的固定时间窗…

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.28 NumPy+Matplotlib:科学可视化的核心引擎

2.28 NumPyMatplotlib&#xff1a;科学可视化的核心引擎 目录 #mermaid-svg-KTB8Uqiv5DLVJx7r {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-KTB8Uqiv5DLVJx7r .error-icon{fill:#552222;}#mermaid-svg-KTB8Uqiv5…

upload-labs安装与配置

前言 作者进行upload-labs靶场练习时&#xff0c;在环境上出了很多问题&#xff0c;吃了很多苦头&#xff0c;甚至改了很多配置也没有成功。 upload-labs很多操作都是旧时代的产物了&#xff0c;配置普遍都比较老&#xff0c;比如PHP版本用5.2.17&#xff08;还有中间件等&am…

【OS】AUTOSAR架构下的Interrupt详解(下篇)

目录 3.代码分析 3.1中断配置代码 3.2 OS如何找到中断处理函数 3.3 Os_InitialEnableInterruptSources实现 3.4 Os_EnableInterruptSource 3.5 DisableAllInterrupts 3.5.1Os_IntSuspendCat1 3.5.2 Os_InterruptDisableAllEnter 3.5.3 Disable二类中断 3.5.4 Disable一…

Nginx知识

nginx 精简的配置文件 worker_processes 1; # 可以理解为一个内核一个worker # 开多了可能性能不好events {worker_connections 1024; } # 一个 worker 可以创建的连接数 # 1024 代表默认一般不用改http {include mime.types;# 代表引入的配置文件# mime.types 在 ngi…

RabbitMQ快速上手及入门

概念 概念&#xff1a; publisher&#xff1a;生产者&#xff0c;也就是发送消息的一方 consumer&#xff1a;消费者&#xff0c;也就是消费消息的一方 queue&#xff1a;队列&#xff0c;存储消息。生产者投递的消息会暂存在消息队列中&#xff0c;等待消费者处理 exchang…

DeepSeek本地部署的一些问题记录

1、模型怎么不保存到C盘&#xff1a;关掉ollama之后&#xff0c;设置环境变量&#xff1a;OLLAMA_MODELS&#xff0c;环境变量的地址&#xff0c;改为你想要的地址&#xff0c;参考文章&#xff1a; https://blog.csdn.net/u012151594/article/details/142062199 2、ollama rm…