Qt下實現支援多執行緒的單例模式

2021-09-01 02:48:23 字數 3555 閱讀 7901

實現單例模式的**很多。

本文的單例模式實現**是本人一直在工程專案中使用的,現拿出和大家交流分享。

本文實現的單例模式,支援多執行緒,採用雙重校驗檢索的方式,整合析構類,杜絕記憶體洩漏,穩定性好。 使用c++/qt的朋友們可以了解一下。

不再廢話,直接上**。

標頭檔案makelog.h

#include #include class makelog: public qobject

}return m_pinstance;

}private:

makelog(){}

makelog(const makelog&){}

makelog& operator ==(const makelog&){}

static makelog* m_pinstance; //類的指標

static qmutex m_mutex;

public:

class cgarbo //專用來析構m_pinstance指標的類}};

static cgarbo m_garbo;

};

makelog.cpp檔案

makelog* makelog::m_pinstance = null;

makelog::cgarbo m_garbo;

qmutex makelog::m_mutex;

支援多執行緒,無記憶體洩漏的單例模式就實現了。

下面舉例說明具體的使用:

在標頭檔案中加入乙個public函式、乙個public變數。

public:

void readfile();

qstring m_config;

在原始檔中加入函式具體實現,使得readfile()或m_config有實際的意義。

那麼,在乙個工程內的其他類中,只需做兩個步驟,就可以使用這個readfile()函式和m_config變數了。

步驟1:包含標頭檔案

#include 「makefile.h」

步驟2:通過單例類入口呼叫函式或變數

makelog::getinstance()->readfile(); //使用函式

makelog::getinstance()->m_config; //使用變數

單例是一種軟體設計模式,採用單例模式書寫的類可以確保在乙個工程中只有乙個物件例項。再通俗點,就是乙個類寫好了之後,就不需要也無法再把這個類例項化了,因為寫這個類的時候已經確保了有且僅有乙個已經例項化的物件。

這樣不是很蠢麼?花了這麼多功夫寫了乙個類,你告訴我這個類沒法用來new出物件了?那我怎麼使用這個類?我寫個配合靜態變數的靜態函式,使用起來不是更方便?

當然不蠢,非但不蠢,而且單例模式是所有設計模式中使用最為頻繁的乙個設計模式。沒法new出物件,因為單例模式已經幫你new了乙個物件,而且讓你的工程中只有這個物件了;使用這個物件只需要包含標頭檔案,然後呼叫介面指標函式就可以了;靜態的全域性函式或變數**實現起來方便,但是不具有類的封裝性和靈活性。

首先要清楚類例項化無非就是三種方式:

1)採用建構函式例項化;

2)用拷貝函式實現例項化;

3)賦值操作實現例項化。

所以,只需要把這個類的建構函式、拷貝函式、賦值操作寫成私有的,就無法呼叫這些函式,自然就無法例項化了。

正如上文所示的幾個函式:

private:

makelog(){} //建構函式

makelog(const makelog&){} //拷貝函式

makelog& operator ==(const makelog&){} //賦值操作符重寫

當然,如果有一些初始化的操作,也可以寫在私有建構函式的雙括號內。

廣泛採用的做法就是在寫乙個public的函式作為介面,這個函式返回單例類唯一例項的指標。

最簡單的寫法如下:

makelog* getinstance()

return m_pinstance;

}makelog* m_pinstance; //唯一例項的指標

這個寫法看著真不錯,可是這麼寫遇到了乙個小小的悖論。

「我如何去呼叫執行這個getinstance()函式啊,對,我需要乙個例項化物件才能去執行!那我去new個物件,等等,唯一的例項化物件是通過這個函式才能找到的啊!」

有方法解決麼,當然,類的靜態方法不需要例項化物件,用

類名::方法()

的形式就可以呼叫執行了,所以把getinstance()函式前加乙個static就好了。

但是靜態方法只能使用靜態成員變數啊,那就把唯一例項的指標m_pinstance也變成static的吧。

ok,這樣有沒有隱患啊?隱患?static型別的instance存在靜態儲存區,每次呼叫時,都指向的同乙個物件。非但沒有隱患,簡直堪稱完美!

現在上面的**就變成這樣:

public:

static makelog* getinstance()

return m_pinstance;

}private:

static makelog* m_pinstance; //唯一例項指標

這樣寫完全沒有問題,但是不支援多執行緒的呼叫。因為new makelog()需要時間,所以當兩個執行緒同時判斷m_pinstance ==null,同時執行了m_pinstance = new makelog()這句**,問題就大了。

為了解決3.3節產生的bug,廣泛採用的方式是雙重校驗檢索的方法。

就是利用互斥鎖(用來保證鎖內**最多只有乙個執行緒在同時執行)的方式,確保不會出現兩個執行緒同時new出這個單例類的唯一例項的情況發生。

具體**如下:

static makelog* getinstance()

}return m_pinstance;

}

至此雙重校驗檢索解決多執行緒問題的單例問題就解決了。當然還可以用原子鎖的方法來解決,但是靈活性不強(也可能是我太外行,靈***來—。—),這裡就不介紹了。

解決單例類的記憶體析構主要就是解決static makelog* m_pinstance這個指標的析構問題(畢竟其他的可以不用指標的嘛)。我總結覺得寫乙個專門用來析構的類是最方便有效和無腦的方法了,推薦給大家。

具體就是在單例類中寫乙個類:

public:

class cgarbo //專用來析構m_pinstance指標的類}};

static cgarbo m_garbo; //宣告乙個靜態的物件

然後在cpp檔案中宣告一下 makelog::cgarbo m_garbo就可以了。

這個類只有析構函式,析構函式的作用就是delete單例唯一物件的指標。

析構類宣告乙個static物件,因為靜態物件系統會在關閉程式時自動析構,就可以執行到析構函式內部的**了。

多執行緒環境下實現單例模式

1 餓漢式 就是在使用類時就將物件建立完畢 例項 public class myobject public static myobject getinstance 測試 public static void main string args 結果 可見hashcode的值一樣的。所有相同物件 2 懶...

多執行緒下的單例模式

單例模式分為兩種 懶漢單例模式和餓漢式單例模式 public class singleton private static singleton single null public static singleton getinstance return single 在單執行緒中,這樣寫,不會存在任...

多執行緒下的單例模式

在多執行緒下的singleton模式是有弊端的,但如何解決呢?辦法是使用lock機制。今天研究的lock機制,並且順便了解了些關於多執行緒的cpu層面的機制。在單個cpu的環境下,在系統的某一時間下cpu只能做一件事情,乙個時間片 slice 這個是cpu執行最小單位。在系統中有多個程序看起來好像是...