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