單例設計模式下的多線程數據共享(C++)

#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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章