七、单例设计模式共享数据分析、解决,call_once

在这里插入图片描述

1.设计模式

程序灵活,维护起来可能方便,用设计模式理念写出来的代码很晦涩,但是别人接管、阅读代码都会很痛苦
老外应付特别大的项目时,把项目的开发经验、模块划分经验,总结整理成设计模式
中国零几年设计模式刚开始火时,总喜欢拿一个设计模式往上套,导致一个小小的项目总要加几个设计模式,本末倒置
设计模式有其独特的优点,要活学活用,不要深陷其中,生搬硬套

2.单例设计模式:

整个项目中,有某个或者某些特殊的类,只能创建一个属于该类的对象。
单例类:只能生成一个对象。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <list>
#include <thread>
#include <mutex>
using namespace std;


class MySigletonClass
{
public:
	static MySigletonClass* GetInstance()
	{
		if (nullptr == instance_)
		{
			instance_ = new MySigletonClass();
			MyReleaseClass my_release;
		}
		std::cout << "创建的MySigletonClass对象地址:" << &instance_ << std::endl;
		return instance_;
	}

	void TestFun()
	{
		std::cout << "单例测试" << std::endl;
	}
private:
	MySigletonClass(){}//构造函数私有化,不能直接创建类对象
	static MySigletonClass* instance_;

	class MyReleaseClass //类中套类,用来释放对象
	{
	public:
		~MyReleaseClass()
		{
			if (MySigletonClass::instance_)
			{
				delete MySigletonClass::instance_;
				MySigletonClass::instance_ = nullptr;
				std::cout << "调用MyRealseClass的析构函数,释放MySigletonClass::instance_" << std::endl;
			}
		}
	};
};

MySigletonClass* MySigletonClass::instance_ = nullptr;

int main(int argc, char* argv[])
{
	//MySigletonClass a;//构造函数私有化了,不能直接构造对象

	MySigletonClass* my_instance_p1 = MySigletonClass::GetInstance();//调用GetInstance的时候创建了类对象
	MySigletonClass* my_instance_p2 = MySigletonClass::GetInstance();//实际上创建的是同一个对象指针
	my_instance_p1->TestFun();
	MySigletonClass::GetInstance()->TestFun();//返回的是一个类指针
	system("pause");
	return 0;
}

3.单例设计模式共享数据分析、解决

在多线程程序中,如果对共享数据只有只读操作,没有问题。
面临问题: 需要在自己创建的线程中来创建单例类的对象,这种线程可能不止一个。我们可能面临GetInstance()这种成员函数需要互斥。
可以在加锁前判断instance_是否为空,否则每次调用MySigletonClass::GetInstance()都要加锁,十分影响效率。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <list>
#include <thread>
#include <mutex>
using namespace std;


std::mutex resource_mutex;

class MySigletonClass
{
public:
	static MySigletonClass* GetInstance()
	{
		//提高效率
		//(1)如果if (nullptr != instance_)成立,肯定表示instance_已经被new过了
		//(2)如果if (nullptr == instance_)成立,不代表instance_一定没被new过

		if (nullptr == instance_)//双重锁定,双重检查
		{
			std::unique_lock<std::mutex> mu_mutex(resource_mutex);//自动加锁
			if (nullptr == instance_)
			{
				instance_ = new MySigletonClass();
				MyReleaseClass my_release;
			}
			std::cout << "创建的MySigletonClass对象地址:" << &instance_ << std::endl;
		}
		return instance_;
	}

	void TestFun()
	{
		std::cout << "单例测试" << std::endl;
	}
private:
	MySigletonClass(){}//构造函数私有化,不能直接创建类对象
	static MySigletonClass* instance_;

	class MyReleaseClass //类中套类,用来释放对象
	{
	public:
		~MyReleaseClass()
		{
			if (MySigletonClass::instance_)
			{
				delete MySigletonClass::instance_;
				MySigletonClass::instance_ = nullptr;
				std::cout << "调用MyRealseClass的析构函数,释放MySigletonClass::instance_" << std::endl;
			}
		}
	};
};

MySigletonClass* MySigletonClass::instance_ = nullptr;

void StartThread()
{
	std::cout << "我的线程执行了" << std::endl;
	MySigletonClass* p_a = MySigletonClass::GetInstance();
	p_a->TestFun();
	std::cout << "我的线程执行完毕了" << std::endl;
	return;
}

int main(int argc, char* argv[])
{
	//MySigletonClass a;//构造函数私有化了,不能直接构造对象

	MySigletonClass* my_instance_p1 = MySigletonClass::GetInstance();//调用GetInstance的时候创建了类对象
	MySigletonClass* my_instance_p2 = MySigletonClass::GetInstance();//实际上创建的是同一个对象指针
	my_instance_p1->TestFun();
	MySigletonClass::GetInstance()->TestFun();//返回的是一个类指针


	std::thread t1(StartThread);
	std::thread t2(StartThread);
	t1.join();
	t2.join();

	system("pause");
	return 0;
}

4.std::call_once():

函数模板,该函数的第一个参数为标记,第二个参数是一个函数名(如a())。
功能:能够保证函数a()只被调用一次。具备互斥量的能力,而且比互斥量消耗的资源更少,更高效。
call_once()需要与一个标记结合使用,这个标记为std::once_flag;其实once_flag是一个结构,call_once()就是通过标记来决定函数是否执行,调用成功后,就把标记设置为一种已调用状态。

多个线程同时执行时,一个线程会等待另一个线程先执行。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <list>
#include <thread>
#include <mutex>
using namespace std;


std::mutex resource_mutex;
std::once_flag flag;

class MySigletonClass
{
public:
	static void CreateInstance()//只被调用一次
	{
		std::chrono::milliseconds dura(20000);//休息20秒
		std::this_thread::sleep_for(dura);
		std::cout << "CreateInstance()被执行了" << std::endl;
		instance_ = new MySigletonClass();
		MyReleaseClass my_release;
	}

	static MySigletonClass* GetInstance()
	{
		//提高效率
		//(1)如果if (nullptr != instance_)成立,肯定表示instance_已经被new过了
		//(2)如果if (nullptr == instance_)成立,不代表instance_一定没被new过

		//if (nullptr == instance_)//双重锁定,双重检查
		//{
		//	std::unique_lock<std::mutex> mu_mutex(resource_mutex);//自动加锁
		//	if (nullptr == instance_)
		//	{
		//		instance_ = new MySigletonClass();
		//		MyReleaseClass my_release;
		//	}
		//	std::cout << "创建的MySigletonClass对象地址:" << &instance_ << std::endl;
		//}

		//两个线程同时执行到这里的时候,其中一个线程要等另外一个线程执行完毕CreateInstance()
		std::call_once(flag, CreateInstance);
		std::cout << "call_once执行完毕" << std::endl;
		return instance_;
	}

	void TestFun()
	{
		std::cout << "单例测试" << std::endl;
	}
private:
	MySigletonClass(){}//构造函数私有化,不能直接创建类对象
	static MySigletonClass* instance_;

	class MyReleaseClass //类中套类,用来释放对象
	{
	public:
		~MyReleaseClass()
		{
			if (MySigletonClass::instance_)
			{
				delete MySigletonClass::instance_;
				MySigletonClass::instance_ = nullptr;
				std::cout << "调用MyRealseClass的析构函数,释放MySigletonClass::instance_" << std::endl;
			}
		}
	};
};

MySigletonClass* MySigletonClass::instance_ = nullptr;

void StartThread()
{
	std::cout << "我的线程执行了" << std::endl;
	MySigletonClass* p_a = MySigletonClass::GetInstance();
	p_a->TestFun();
	std::cout << "我的线程执行完毕了" << std::endl;
	return;
}

int main(int argc, char* argv[])
{
	//MySigletonClass a;//构造函数私有化了,不能直接构造对象

	MySigletonClass* my_instance_p1 = MySigletonClass::GetInstance();//调用GetInstance的时候创建了类对象
	MySigletonClass* my_instance_p2 = MySigletonClass::GetInstance();//实际上创建的是同一个对象指针
	my_instance_p1->TestFun();
	MySigletonClass::GetInstance()->TestFun();//返回的是一个类指针


	std::thread t1(StartThread);
	std::thread t2(StartThread);
	t1.join();
	t2.join();

	system("pause");
	return 0;
}

更多推荐