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

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

    • (1)设计模式大概谈
    • (2)单例设计模式
    • (3)单例设计模式共享数据问题分析、解决
    • (4)std::call_once()

(1)设计模式大概谈

“设计模式”:代码的一些写法(这些写法跟常规写法不一样);程序灵活,维护起来方便,但是别人接管,阅读代码会比较困难
用设计模式理念写出来的代码很晦涩;《head first》
设计之初是为了应付特别大的项目时,把项目的开发经验、模块划分、总结整理成设计模式(先有开发需求,后有理论总结和整理)
设计模式有它独特的优点,但是要活学活用,不要生搬硬套,小的代码不需要往设计模式套。

(2)单例设计模式

单例设计模式使用频率高;
单例:整个项目中,有某个或者某些特殊的类,属于该类的对象,只能创建一个,多了创建不了。
单例类:

#include 
#include
using namespace std;
class MyCAS//这是一个单例类
{
private:
	MyCAS() {};//私有化了构造函数
private:
	static MyCAS *m_instance;//静态成员函数
public:
	static MyCAS *GetInstance()
	{
		if (m_instance == NULL)
		{
			m_instance = new MyCAS();
			static CGarhuishou cl;
		}
		return m_instance;
	}
	class CGarhuishou//类中套类,用来释放对象
	{
	public:
		~CGarhuishou()//类的析构函数中
		{
			if (MyCAS::m_instance)
			{
				delete MyCAS::m_instance;
				MyCAS::m_instance = NULL;
			}
		}
	};

	void func()
	{
		cout << "测试" << endl;
	}
};
//类静态变量初始化
MyCAS *MyCAS::m_instance = NULL;
int main()
{
	MyCAS *p_a = MyCAS::GetInstance();//创建一个对象,返回该类对象的指针
	//MyCAS *p_b = MyCAS::GetInstance();//创建一个对象,返回该类对象的指针
	p_a->func();
	MyCAS::GetInstance()->func();
}

(3)单例设计模式共享数据问题分析、解决

面临的问题:需要在我们自己创建的线程(而不是主线程中)来创建MyCAS这个单例类的对象,这种线程可能不止一个(最少两个)
我们可能会面临GetInstance()这种成员函数需要互斥
更改代码:

#include 
#include
using namespace std;
class MyCAS//这是一个单例类
{
private:
	MyCAS() {};//私有化了构造函数
private:
	static MyCAS *m_instance;//静态成员函数
public:
	static MyCAS *GetInstance()
	{
		if (m_instance == NULL)
		{
			m_instance = new MyCAS();
			static CGarhuishou cl;
		}
		return m_instance;
	}
	class CGarhuishou//类中套类,用来释放对象
	{
	public:
		~CGarhuishou()//类的析构函数中
		{
			if (MyCAS::m_instance)
			{
				delete MyCAS::m_instance;
				MyCAS::m_instance = NULL;
			}
		}
	};

	void func()
	{
		cout << "测试" << endl;
	}
};
//类静态变量初始化
MyCAS *MyCAS::m_instance = NULL;
//线程入口函数
void mythread()
{
	cout << "我的线程开始执行了" << endl;
	MyCAS *p_a = MyCAS::GetInstance();//这里可能会有问题
	cout << "我的线程执行完毕了" << endl;
	return;
}
int main()
{
	std::thread mytobj1(mythread);
	std::thread mytobj2(mythread);
	mytobj1.join();
	mytobj2.join();
	return 0;
}

虽然这两个线程是同一个入口函数,但是这是两个线程,所以这里会有两个流程(两条通路)同时执行mythread这个函数。
加互斥量:

#include 
#include
#include
using namespace std;

std::mutex resource_mutex;
class MyCAS//这是一个单例类
{
private:
	MyCAS() {};//私有化了构造函数
private:
	static MyCAS *m_instance;//静态成员函数
public:
	static MyCAS *GetInstance()
	{//提高效率
		//如果if (m_instance != NULL)条件成立,则肯定表示m_instance已经被new过了
		//如果if (m_instance == NULL)条件成立,不代表m_instance一定没被mew过
		if (m_instance == NULL)//双重锁定(双重检查)
		{
			std::unique_lock <std::mutex> mymutex(resource_mutex);//自动加锁
			if (m_instance == NULL)
			{
				m_instance = new MyCAS();
				static CGarhuishou cl;
			}
		}
		return m_instance;
	}
	class CGarhuishou//类中套类,用来释放对象
	{
	public:
		~CGarhuishou()//类的析构函数中
		{
			if (MyCAS::m_instance)
			{
				delete MyCAS::m_instance;
				MyCAS::m_instance = NULL;
			}
		}
	};

	void func()
	{
		cout << "测试" << endl;
	}
};
//类静态变量初始化
MyCAS *MyCAS::m_instance = NULL;
//线程入口函数
void mythread()
{
	cout << "我的线程开始执行了" << endl;
	MyCAS *p_a = MyCAS::GetInstance();//这里可能会有问题
	cout << "我的线程执行完毕了" << endl;
	return;
}
int main()
{
	std::thread mytobj1(mythread);
	std::thread mytobj2(mythread);
	mytobj1.join();
	mytobj2.join();
	return 0;
}

(4)std::call_once()

C++11引入的函数,该函数的第二个参数是一个函数名a();
call_once功能就是能够保证函数a()只被调用一次
具备互斥量的能力,而且效率上比互斥量消耗的资源更少
call_once()需要与一个标记结合使用,这个标记std::once_flag;其实once_flag是一个结构;
call_once()就是通过这个标记来决定对应的函数a()是否执行,调用call_once()成功后,call_once()就把这个标记设置为一种已读的状态;后续再次调用call_once(),只要once_flag被设置为了“已调用”状态,那么对应的函数a()就不会再被执行了

// ConsoleApplication7.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include 
#include
#include
using namespace std;

std::mutex resource_mutex;
std::once_flag g_flag;//这是个系统定义的标记

class MyCAS//这是一个单例类
{
	static void CreateInstance()//只被调用一次
	{
		std::chrono::milliseconds dura(20000);
		std::this_thread::sleep_for(dura);
		m_instance = new MyCAS();
		cout << "CreateInstance()被执行了" << endl;
		static CGarhuishou c1;
	}
private:
	MyCAS() {};//私有化了构造函数
private:
	static MyCAS *m_instance;//静态成员函数

public:
	static MyCAS *GetInstance()
	{//提高效率
		//如果if (m_instance != NULL)条件成立,则肯定表示m_instance已经被new过了
		//如果if (m_instance == NULL)条件成立,不代表m_instance一定没被mew过
		//if (m_instance == NULL)//双重锁定(双重检查)
		//{
		//	std::unique_lock  mymutex(resource_mutex);//自动加锁
		//	if (m_instance == NULL)
		//	{
		//		m_instance = new MyCAS();
		//		static CGarhuishou cl;
		//	}
		//}
		std::call_once(g_flag, CreateInstance);//假设两个线程同时开始执行到这里,其中一个线程要等另外一个线程执行完毕CreateInstance,
		cout << "call_once()执行完毕" << endl;
		return m_instance;
	}
	class CGarhuishou//类中套类,用来释放对象
	{
	public:
		~CGarhuishou()//类的析构函数中
		{
			if (MyCAS::m_instance)
			{
				delete MyCAS::m_instance;
				MyCAS::m_instance = NULL;
			}
		}
	};

	void func()
	{
		cout << "测试" << endl;
	}
};
//类静态变量初始化
MyCAS *MyCAS::m_instance = NULL;
//线程入口函数
void mythread()
{
	cout << "我的线程开始执行了" << endl;
	MyCAS *p_a = MyCAS::GetInstance();//这里可能会有问题
	cout << "我的线程执行完毕了" << endl;
	return;
}
int main()
{
	std::thread mytobj1(mythread);
	std::thread mytobj2(mythread);
	mytobj1.join();
	mytobj2.join();
	return 0;
}

你可能感兴趣的:(C++11并发与多线程)