C++11并发与多线程笔记(7) 单例设计模式共享数据分析、解决,call_once

C++11并发与多线程笔记(7) 单例设计模式共享数据分析、解决,call_once

1.设计模式

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

2.单例设计模式:

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

# include<iostream>
using namespace std;
class MyClass {//单例类
private:
	MyClass(){}//私有化构造函数
	static MyClass* m_instance;//静态成员变量
public:
	static MyClass* getInstance() {//静态成员函数用于创建对象
		if (m_instance == NULL) {
			m_instance = new MyClass();
		}
		return m_instance;
	}
	void func() {
		cout << "测试" << endl;
	}
	
};
MyClass* MyClass::m_instance = NULL;//类内定义,类外初始化

int main() {
	//创建一个对象,返回该类(Myclass)对象的指针
	MyClass* p_a = MyClass::getInstance();
	p_a->func();//测试
}

如果觉得在单例模式new了一个对象,而没有自己delete掉,这样不合理。可以增加一个类中类CGarhuishou,new一个单例类时创建一个静态的CGarhuishou对象,这样在程序结束时会调用CGarhuishou的析构函数,释放掉new出来的单例对象。

# include<iostream>
using namespace std;
class MyClass {//单例类
private:
	MyClass(){}//私有化构造函数
	static MyClass* m_instance;//静态成员变量
public:
	static MyClass* getInstance() {//静态成员函数用于创建对象
		if (m_instance == NULL) {
			m_instance = new MyClass();
			static CGarhuishou cl; //释放对象
		}
		return m_instance;
	}

	class CGarhuishou {//类中套类,用来释放对象
	public:
		~CGarhuishou() {
			if (MyClass::m_instance) {
				delete MyClass::m_instance;
				MyClass::m_instance = NULL;
			}
		}
	};
	void func() {
		cout << "测试" << endl;
	}
	
};
MyClass* MyClass::m_instance = NULL;//类内定义,类外初始化

int main() {
	//创建一个对象,返回该类(Myclass)对象的指针
	MyClass* p_a = MyClass::getInstance();
	p_a->func();//测试
}

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

面临问题:需要在自己创建的线程(而不是主线程)中来创建单例类的对象,这种线程可能不止一个。我们可能面临getInstance()这种成员函数需要互斥。
解决方法:可以在
加锁前判断m_instance是否为空
,否则每次调用MyClass::getInstance()都要加锁,十分影响效率。

# include<iostream>
# include<thread>
#include<mutex>
using namespace std;
mutex mutex1;
class MyClass {//单例类
private:
	MyClass(){}//私有化构造函数
	static MyClass* m_instance;//静态成员变量
public:
	static MyClass* getInstance() {
		//双重锁定 提高效率
		if (m_instance == NULL) {
			unique_lock<mutex> myMutex(mutex1);//单独加此代码,每一次判断创建新对象,都要加锁
			if (m_instance == NULL) {
				m_instance = new MyClass();
				static CGarhuishou cl;
			}
		}
		return m_instance;
	}

	class CGarhuishou {//类中套类,用来释放对象
	public:
		~CGarhuishou() {
			if (MyClass::m_instance) {
				delete MyClass::m_instance;
				MyClass::m_instance = NULL;
			}
		}
	};
	void func() {
		cout << "测试" << endl;
	}
};
MyClass* MyClass::m_instance = NULL;//类内定义,类外初始化

//线程入口函数
void mythread() {
	cout << "myPrint线程开始执行了 " << endl;
	MyClass* p_a = MyClass::getInstance();
	cout << "myPrint线程结束执行了"  << endl;
}
int main() {
	thread myobj1(mythread);
	thread myobj2(mythread);
	myobj1.join();
	myobj2.join();
}

4.std::call_once():

函数模板,该函数的第一个参数标记第二个参数是一个函数名(如a())。
功能:能够保证函数a()只被调用一次。具备互斥量的能力,而且比互斥量消耗的资源更少,更高效。

  • call_once()需要与一个标记结合使用,这个标记为std::once_flag;其实once_flag是一个结构,call_once()就是通过标记来决定函数是否执行,调用成功后,就把标记设置为一种已调用状态

  • 多个线程同时执行时,使用call_once(),一个线程会等待另一个线程先执行。

# include<iostream>
# include<thread>
#include<mutex>
using namespace std;
once_flag g_flag;//标记来决定函数是否执行

class MyClass {//单例类
private:
	MyClass() {}//私有化构造函数
	static MyClass* m_instance;//静态成员变量
public:
	//用于call_once函数的第二个参数,保证其只被调用一次
	static void CreateInstance() {
		m_instance = new MyClass;
		static CGarhuishou cl;
	}
	//两个线程同时执行到这里,其中一个线程要等另外一个线程执行完毕
	static MyClass* getInstance() {
		call_once(g_flag,CreateInstance);
		return m_instance;
	}

	class CGarhuishou {//类中套类,用来释放对象
	public:
		~CGarhuishou() {
			if (MyClass::m_instance) {
				delete MyClass::m_instance;
				MyClass::m_instance = NULL;
			}
		}
	};
	void func() {
		cout << "测试" << endl;
	}
};
MyClass* MyClass::m_instance = NULL;//类内定义,类外初始化

//线程入口函数
void mythread() {
	cout << "myPrint线程开始执行了 " << endl;
	MyClass* p_a = MyClass::getInstance();
	cout << "myPrint线程结束执行了"  << endl;
}
int main() {
	thread myobj1(mythread);
	thread myobj2(mythread);
	myobj1.join();
	myobj2.join();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值