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

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.kler.cn/a/532318.html

相关文章:

  • 生成式AI安全最佳实践 - 抵御OWASP Top 10攻击 (上)
  • Codeforces Round 1002 (Div. 2)(部分题解)
  • Python 科学计算
  • 股票入门知识
  • PyTorch数据建模
  • 如何运行Composer安装PHP包 安装JWT库
  • http请求中的headers和body内容设置
  • 毕业设计:基于深度学习的高压线周边障碍物自动识别与监测系统
  • 如可安装部署haproxy+keeyalived高可用集群
  • 【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.23 稀疏矩阵:CSR格式的存储与运算
  • fiddler笔记
  • 基于Flask的抖音用户浏览行为分析系统的设计与实现
  • RocketMQ实战—3.基于RocketMQ升级订单系统架构
  • Rust 中的模块系统:控制作用域与私有性
  • ThreadLocal使用和原理
  • 【Unity2D 2022:UI】创建滚动视图
  • CTFHub信息泄露PHPINFO
  • Qt展厅播放器/多媒体播放器/中控播放器/帧同步播放器/硬解播放器/监控播放器
  • win32汇编环境,对话框程序生成选项卡(属性页\标签)控件及运用
  • swagger使用指引
  • 网站快速收录:如何优化网站H标签使用?
  • 【操作系统】同步与异步,同步与互斥
  • 【学习笔记】计算机图形学的几何数学基础知识
  • 【Redis】主从模式,哨兵,集群
  • 每日一题——小根堆实现堆排序算法
  • 低通滤波算法的数学原理和C语言实现