線程安全的單例模式_第1頁
線程安全的單例模式_第2頁
線程安全的單例模式_第3頁
線程安全的單例模式_第4頁
線程安全的單例模式_第5頁
已閱讀5頁,還剩2頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、線程安全的單例模式、/、刖旨單例模式(SingletonPattern)是最簡單的、也是我們很常用的一種設(shè)計模式。保證一個類僅有一個實例,并提供一個該實例的全局訪問點。那么在多線程的環(huán)境,怎么才能更好的確保線程安全呢?實現(xiàn)1餓.漢模式餓漢模式使用一個靜態(tài)成員變量,程序啟動即完成構(gòu)造,不用考慮線程安全的問題,C+11中static的特性:如果當變量在初始化的時候,并發(fā)同時進入聲明語句,并發(fā)線程將會阻塞等待初始化結(jié)束。classSingletonpublic:staticSingleton*GetInstance()returninstance_;if(instance_!=nullptr)del

2、eteinstance_;private:Singleton()=default;Singleton&operator=(constSingleton&)=delete;Singleton(constSingleton&singleton2)=delete;private:staticSingleton*instance_;_intmain()Singleton*s1=Singleton:GetInstance();Singleton:DestreyInstance();return0;關(guān)于資源的釋放上例中我們使用了一個靜態(tài)的成員函數(shù)來釋放堆上的資源,需要手動調(diào)用,并不是很方便。我們可以使用智

3、能指針或者一個內(nèi)部類來實現(xiàn)資源的自動釋放,也更符合Moderncpp的風格。接下來我們演示如何使用一個內(nèi)部類來優(yōu)化餓漢模式。classSingletonpublic:staticSingleton*GetInstance()returninstance_;if(instance_!=nullptr)deleteinstance_;private:classGCpublic:GC()可以在這里銷毀所有的資源,例如:b連接、文件句柄等if(instance_!=nullptr)deleteinstance_;instance_=nullptr;staticGCgc;p!:Singleton()=d

4、efault;Singleton&operator=(constSingleton&)=delete;Singleton(constSingleton&singleton2)=delete;private:staticSingleton*instance_;_懶漢模式餓漢方式不論是否需要使用該對象都將其定義出來,可能浪費了內(nèi)存,或者減慢了程序的啟動速度。所以使用懶漢模式進行優(yōu)化,懶漢模式即延遲構(gòu)造對象,在第一次使用該對象的時候才進行new該對象。而懶漢模式會存在線程安全問題,最出名的解決方案就是Double-CheckedLockingPattern(DCLP)(雙檢鎖)。使用兩次判斷來解決線

5、程安全問題并且提高效率。classSingletonpublic:staticSingleton&GetInstance()if(instance_=nullptr)std:lock_guardlock(mutex_);if(instance_=nullptr)instance_.reset(newSingleton);return*instance_;Singleton()=default;private:Singleton()=default;Singleton(constSingleton&)=delete;Singleton&operator=(constSingleton&)=del

6、ete;private:staticstd:unique_ptrinstance_;staticstd:mutexmutex_;std:unique_ptrSingleton:instance_;std:mutexSingleton:mutex_;雙檢鎖的問題DCLP實際上也是存在這嚴重的線程安全問題的,具體參考原文中有這樣一段話:Consideragainthelinethatinitializespinstanee:pInstance=newSingleton;Thisstatementcausesthreethingstohappen:Step1:Allocatememorytohold

7、aSingletonobject.Step2:ConstructaSingletonobjectintheallocatedmemory.Step3:Makepinstaneepointtotheallocatedmemory.Ofcriticalimportanceistheobservationthatcompilersarenotconstrainedtoperformthesestepsinthisorder!Inparticular,compilersaresometimesallowedtoswapsteps2and3.Whytheymightwanttodothatisaques

8、tionwelladdressinamoment.Fornow,letsfocusonwhathappensiftheydo.也就是我們在instance_=newSingleton;時發(fā)生了三件事情:申請一塊內(nèi)存來保存單例對象。在申請的內(nèi)存中調(diào)用構(gòu)造函數(shù)。將內(nèi)存的地址賦值給instance_。不同的編譯器表現(xiàn)不一樣,它們并不會嚴格按照這個順序執(zhí)行,尤其是有時候允許交換第二步和第三步!也就是說可能會先將內(nèi)存地址賦值給instance_然后再調(diào)用構(gòu)造函數(shù)。這樣就會有嚴重的線程安全問題,比如:線程A剛好申請完內(nèi)存并將該內(nèi)存地址賦值給instance_但是此時還沒調(diào)用構(gòu)造函數(shù),又剛好此時線程B執(zhí)行到

9、了if(instance_=nullptr)判斷instance_并不為空,返回了該變量,然后調(diào)用了該對象的函數(shù),但是該對象還沒進行構(gòu)造。其實就是編譯優(yōu)化導致的一個亂序(reorder)的問題。懶漢模式進一步優(yōu)化1.使用std:call_oneeC+11中std:call_once和std:once_flag配合使用使得函數(shù)可以線程安全的只調(diào)用一次。classSingletonpublic:staticSingleton&GetInstance()staticstd:once_flags_flag;std:call_once(s_flag,&()instance_.reset(newSingl

10、eton););return*instance_;Singleton()=default;voidPrintAddress()conststd:coutthisstd:endl;private:Singleton()=default;Singleton(constSingleton&)=delete;Singleton&operator=(constSingleton&)=delete;private:staticstd:unique_ptrinstance_;std:unique_ptrSingleton:instance_;.使用內(nèi)存屏障classSingletonpublic:stati

11、cSingleton*GetInstance()Singleton*tmp=instance_oad(std:memory_order_relaxed);獲取內(nèi)存屏障std:atomic_thread_fence(std:memory_order_acquire);if(tmp=nullptr)std:lock_guardlock(mutex_);tmp=instance_oad(std:memory_order_relaxed);if(tmp=nullptr)tmp=newSingleton;釋放內(nèi)存屏障std:atomic_thread_fence(std:memory_order_rel

12、ease);instance_store(tmp,std:memory_order_relaxed);atexit(Destructor);returntmp;private:staticvoidDestructor()Singleton*tmp=instance_.load(std:memory_order_relaxed);if(nullptr!=tmp)deletetmp;Singleton()=default;Singleton(constSingleton&)Singleton&operator=(constSingleton&)staticstd:atomicinstance_;s

13、taticstd:mutexmutex_;std:atomicSingleton:instance_;std:mutexSingleton:mutex_;最簡單實用的方式好了,說了這么多,前面一頓操作猛如虎,其實最簡單實用的還是靜態(tài)局部變量的方式。classSingletonpublic:Singleton()staticSingleton&GetInstance()staticSingletoninstance;returninstance;private:Singleton()=default;Singleton(constSingleton&)Singleton&operator=(co

14、nstSingleton&);優(yōu)點:“代碼簡潔;“利用靜態(tài)局部變量特性,延遲加載;“利用靜態(tài)局部變量特性,系統(tǒng)自動回收內(nèi)存,自動調(diào)用析構(gòu)函數(shù);“靜態(tài)局部變量初始化時,沒有new操作帶來的cpu指令reorder操作;“c+11靜態(tài)局部變量初始化時,具備線程安全;升級為模板templatevtypenameTclassSingletonpublic:staticT&GetInstance()staticTinstance;returninstance;protected:virtualSingleton()Singleton()Singleton(constSingleton&)Singleton&operator=(constSingleton&);使用方式比如我們有一個普通類DesignPattern,它是全局唯一的,

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論