单例设计模式下的多线程数据共享(C++)

本文详细解析了C++中实现线程安全的单例模式,通过互斥量和call_once函数确保在多线程环境中仅创建一次实例。介绍了如何避免双重实例化问题,并展示了实际代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include <iostream>
#include <thread>
#include <mutex>
using namespace std;

mutex resource_mutex;  //增加互斥量

once_flag g_flag; //系统定义的标记
//较实用的单例类
class MyCAS
{
private:
	 //将构造函数私有化
	MyCAS()
	{

	}
private:
	static MyCAS * m_instance;   //静态成员变量
	 
public:
	/* 
	//与call_once配合使用
	static void CreateInstance()  //只被调用一次的函数
	{
		m_instance = new MyCAS();  
		static CGarhuishou c1;  
	}
	*/
	static MyCAS *GetInstance()  //如果m_instance为空,则创建;否则返回已存在的对象指针
	{
		//如果m_instance != NULL,则表示m_instance肯定被new过了
		//如果m_instance == NULL,不代表m_instance一定没被new过(可能在申请加锁互斥量(为了new)时,被别的线程new了)
		if (m_instance == NULL)  //双重锁定(双重检查),提高效率,避免每次调用GetInstance()都要申请加锁互斥量
		{
			unique_lock<mutex> my_mutex(resource_mutex); //自动加锁解锁
			if (m_instance == NULL)
			{
				m_instance = new MyCAS();  //如果有多个线程,不加互斥量程序就会有问题
				static CGarhuishou c1;  //用来释放m_instance; 
			}
		}

		//call_once(g_flag, CreateInstance);  //call_once,两个线程同时执行到这里,其中一个线程A等待另外一个线程B执行完毕,然后B执行完毕,g_flag被修改为已被执行的状态,A就不再执行。
		return m_instance;
	}
	class CGarhuishou  //类中套类 用来释放对象 
	{

	public:
		~CGarhuishou()
		{
			if (MyCAS::m_instance )
			{
				delete MyCAS::m_instance;
				MyCAS::m_instance = NULL;
			}
		}
	};

};

//类静态变量初始化
MyCAS *MyCAS::m_instance = NULL;
 

void mythread()
{
	cout << "我的线程开始执行了" << endl;
	MyCAS *p_a = MyCAS::GetInstance();  //如果不互斥,会出现的问题:
	cout << "我的线程执行完毕了" << endl;
	return;
}
int main()
{
	//一:设计模式概谈
	//设计模式:代码的一些写法(跟常规写法不太一样)。程序灵活,维护起来可能方便,但别人接管、阅读代码都会很痛苦
	//应付特别大的项目的时候,把项目的开发经验、模块划分经验,总结整理成设计模式
	//小项目强行用设计模式理念写出来的代码是很晦涩的,要活学活用,不要生搬硬套,深陷其中,本末倒置
	//设计模式有独特的优点 


	//二:单例设计模式(使用的频率较高)
	//整个项目中,有某个或某些特殊的类(单例类),属于该类的对象,只能创建1个,多了创建不了。
	//MyCAS a1;   //将构造函数私有化后,无法这样创建对象
	//MyCAS a2;
	//MyCAS *p_a = MyCAS::GetInstance();   //创建一个对象,返回该类对象的指针
	//MyCAS *p_b = MyCAS::GetInstance();   //不会再创建新的,会返回已有的对象的指针


	//三:单例设计模式共享数据问题分析、解决
	//面临的问题:需要在我们自己创建的线程(而不是主线程)中来创建 MyCAS这个单例类的对象,这种线程可能不止一个
	//此时GetInstance()这种成员函数需要互斥
	thread mytobj1(mythread);
	thread mytobj2(mythread);  //线程入口函数均为mythread
	mytobj1.join();
	mytobj2.join();

	 
	//四:std::call_once();  C++11引入的函数,该函数的第二个参数是一个函数名
	//功能是能够保障函数A()只被调用一次
	//具备互斥量的能力,而且效率上比互斥量消耗的资源更少
	//需要与一个标记结合使用。标记是 std::once_flag,是一种结构。就是通过这个标记来决定对应的函数是否执行,执行后会更改once_flag状态


	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值