Singleton設計模式的C 實現

2021-07-03 16:23:22 字數 4163 閱讀 1501

singleton模式

singleton(譯為單件或單態)模式是設計模式中比較簡單而常用的模式。

有些時候在整個應用程式中,會要求某個類有且只有乙個例項,這個時候可以採用singleton模式進行設計。用singleton模式設計的類不僅能保證在應用中只有乙個例項,而且提供了一種非全域性變數的方法進行全域性訪問,稱為全域性訪問點,這樣對於沒有全域性變數概念的純物件導向語言來說是非常方便的,比如c#。

本文用乙個計數器的例子來描述在c#中如何使用singleton模式:計數的值設計為計數器類的乙個私有成員變數,它被4個不同的執行緒進行讀寫操作,為保證計數的正確性,在整個應用當中必然要求計數器類的例項是唯一的。

singleton的實現方式

首先看看教科書方式的singleton標準實現的兩種方法,以下用的是類c#偽**:

方法一:

using system;

namespace cspattern.singleton

static public singleton instance() }

} 方法二:

using system;

namespace cspattern.singleton

static public singleton instance()

return unisingleton;

} } }

singleton模式的實現有兩個技巧:一是使用靜態成員變數儲存「全域性」的例項,確保了唯一性,使用靜態的成員方法instance() 代替 new關鍵字來獲取該類的例項,達到全域性可見的效果。二是將構造方法設定成為private,如果使用new關鍵字建立類的例項,則編譯報錯,以防程式設計時候筆誤。

上面方法二的初始化方式稱為lazy initialization,是在第一次需要例項的時候才建立類的例項,與方法一中類的例項不管用不用一直都有相比,方法二更加節省系統資源。但是方法二在多執行緒應用中有時會出現多個例項化的現象。

假設這裡有2個執行緒:主線程和執行緒1,在建立類的例項的時候可能會遇到一些原因阻塞一段時間(比如網路速度或者需要等待某些正在使用的資源的釋放),此時的運**況如下:

主線程首先去呼叫instance()試圖獲得類的例項,instance()成員方法判斷該類沒有建立唯一例項,於是開始建立例項。由於一些因素,主線程不能馬上建立成功,而需要等待一些時間。此時執行緒1也去呼叫instance()試圖獲得該類的例項,因為此時例項還未被主線程成功建立,因此執行緒1又開始建立新例項。結果是兩個執行緒分別建立了兩次例項,對於計數器類來說,就會導致計數的值被重置,與singleton的初衷違背。解決這個問題的辦法是同步。

使用方法一:

using system;

using system.threading;

namespace cspattern.singleton

static public counter instance()

public void inc() //計數加1。

public int getcounter() //獲得當前計數值。 } }

以下是呼叫counter類的客戶程式,在這裡我們定義了四個執行緒同時使用計數器,每個執行緒使用4次,最後得到的正確結果應該是16:

using system;

using system.io;

using system.threading;

namespace cspattern.singleton.mutilethread

public void dosomework()

報告: 當前counter為: ", thread.currentthread.name.tostring(), mycounter.getcounter().tostring());

} }

public void clientmain() }

} 以下為main函式,本程式的測試入口:

using system;

namespace cspattern.singleton

static public void main(string args) }

} 執行結果如下:

執行緒thread 1報告: 當前counter為: 2

執行緒thread 1報告: 當前counter為: 4

執行緒thread 1報告: 當前counter為: 5

執行緒thread 1報告: 當前counter為: 6

執行緒thread 3報告: 當前counter為: 7

執行緒thread 3報告: 當前counter為: 8

執行緒thread 3報告: 當前counter為: 9

執行緒thread 3報告: 當前counter為: 10

執行緒thread 0報告: 當前counter為: 1

執行緒thread 0報告: 當前counter為: 11

執行緒thread 0報告: 當前counter為: 12

執行緒thread 0報告: 當前counter為: 13

執行緒thread 2報告: 當前counter為: 3

執行緒thread 2報告: 當前counter為: 14

執行緒thread 2報告: 當前counter為: 15

執行緒thread 2報告: 當前counter為: 16

由於系統執行緒排程的不同,每次的執行結果也不同,但是最終結果一定是16。

方法一中由於例項一開始就被建立,所以instance()方法無需再去判斷是否已經存在唯一的例項,而返回該例項,所以不會出現計數器類多次例項化的問題。

使用方法二:

using system;

using system.threading;

using system.runtime.compilerservices;

namespace cspattern.singleton

[methodimpl(methodimploptions.synchronized)] //方法的同步屬性

static public counter_lazy instance()

return unicounter;

} public void inc()

public int getcounter() } }

不知道大家有沒有注意到instance()方法上方的[methodimpl(methodimploptions.synchronized)] 語句,他就是同步的要點,他指定了instance()方法同時只能被乙個執行緒使用,這樣就避免了執行緒0呼叫instance()建立完成例項前線程1就來呼叫instance()試圖獲得該例項。

根據msdn的提示,也可以使用lock關鍵字進行執行緒的加鎖,**如下:

using system;

using system.threading;

namespace cspattern.singleton

static public counter_lazy instance()

return unicounter;

} }

public void inc()

public int getcounter()

} }

lock()是對乙個物件加互斥鎖,只允許乙個執行緒訪問其後大括號中語句塊,直到該語句塊的**執行完才解鎖,解鎖後才允許其他的執行緒執行其語句塊。

還可以使用mutex類進行同步,定義private static mutex mut = new mutex();後,修改instance()如下,同樣可以得到正確的結果:

static public counter_lazy instance()

mut.releasemutex();

return unicounter; }

注意的是,本例中使用方法二要更改方法一的客戶程式,去掉counter_lazy.intance()的注釋,並將counter.intance()注釋。

singleton模式還可以拓展,只要稍加修改,就可以限制在某個應用中只能允許m個例項存在,而且為m個例項提供全域性透明的訪問方法。

c 設計模式 Singleton模式

參考的文件 單例要求乙個類裡面只有乙個例項,並且提供了乙個全域性的訪問點。單例類裡面定義了乙個getinstance的方法,是乙個靜態方法。用於建立自己的唯一例項。在乙個系統裡面要求某個類只有乙個例項才能使用單例模式。比如印表機 或者乙個通訊口進行傳輸。using system using syst...

C 設計模式之Singleton模式

singleton是二十三個設計模式中比較重要也比較經常使用的模式。但是這個模式雖然簡單,實現起來也會有一些小坑,讓我們一起來看看吧!首先我們看看這個設計模式的uml類圖。很清晰的可以看到,有三點是需要我們在實現這個模式的時候注意的地方。其中,私有化構造器是防止外部使用者建立新的例項而靜態方法用於返...

C 設計模式之Singleton

一 功能保證乙個類僅有乙個例項。二 結構圖 三 優缺點 singleton模式是做為 全域性變數 的替代品出現的。所以它具有全域性變數的特點 全域性可見 貫穿應用程式的整個生命期,它也具有全域性變數不具備的性質 同型別的物件例項只可能有乙個。四 實現 教科書上的singleton定義如下 class...