免费观看又色又爽又黄的小说免费_美女福利视频国产片_亚洲欧美精品_美国一级大黄大色毛片

Singleton模式創(chuàng)建、多線程與銷毀的方法是什么

這篇文章主要介紹“Singleton模式創(chuàng)建、多線程與銷毀的方法是什么”,在日常操作中,相信很多人在Singleton模式創(chuàng)建、多線程與銷毀的方法是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Singleton模式創(chuàng)建、多線程與銷毀的方法是什么”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

成都創(chuàng)新互聯(lián)公司公司2013年成立,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項目成都網(wǎng)站建設(shè)、網(wǎng)站制作網(wǎng)站策劃,項目實施與項目整合能力。我們以讓每一個夢想脫穎而出為使命,1280元印江做網(wǎng)站,已為上家服務(wù),為印江各地企業(yè)和個人服務(wù),聯(lián)系電話:18982081108

1         Singleton創(chuàng)建

1.1      GOF Singleton

在GOF著作中對Singleton模式的實現(xiàn)方式如下:

/*解一*/   class Singleton   {   public:   static Singleton *Instance(){                            //1   if( !m_pInstatnce) //2   m_pInstance = new Singleton;//3   return m_pInstance; //4   }   private:   static Singleton *m_pInstatnce;             //5   private:   Singleton();                                                         //6   Singleton(const Singleton&);                             //7   Singleton& operator=(const Singleton&);            //8   ~Singleton();                                                       //9   }   Singleton *Singleton:m_pInstatnce = NULL; //10

在上面的解決方案中,我們只在需要調(diào)用時,才產(chǎn)生一個Singleton的對象。這樣帶來的好處是,如果該對象產(chǎn)生帶來的結(jié)果很昂貴,但不經(jīng)常用到時,是一種非常好的策略。但如果該Instance被頻繁調(diào)用,那么就有人覺得Instance中的判斷降低了效率(雖然只是一個判斷語句^_^),那么我們就把第5條語句該為

static Singleton m_Instatnce;

如此一來,在Instatnce直接返回&m_Instance,而不用做任何判斷,效率也高了。(是不是呢?)

這樣修改后,我們將帶來災(zāi)難性的后果:

1:首先有可能編譯器這關(guān)就沒法通過,說m_Instance該外部變量無法解決(visural C++6.0)

error LNK2001: unresolved external symbol "private: static class Singleton  Singleton::m_Instance" (?m_Instance@Singleton@@0V1@A)

2:如果編譯器這關(guān)通過了就沒問題了么?答案是否定的。

***是不管Instance是否用到,該靜態(tài)變量對象在編譯器編譯時就產(chǎn)生了,即資源消耗是不可避免的;

第二是無法確保編譯器一定先將m_Instance初始化。所以Instance的調(diào)用有可能傳回一個尚沒構(gòu)造的Singleton對象。這也意味著你無法保證任何外部對象所使用的m_Instance是一個被正確初始化的對象。

1.2      Meyers Singleton
我們?nèi)绾谓鉀Q這個問題呢,實際上很簡單。一種非常優(yōu)雅的做法由Scott Meyers***提出,故也稱為Meyers Singleton。它依賴編譯器的神奇技巧。即函數(shù)內(nèi)的static對象只在該函數(shù)***次執(zhí)行時才初始化(請注意不是static常量)。

/*解二*/   class Singleton   {   public:   static Singleton *Instance(){                            //1   static Singleton sInstance; //2   return &sInstance; //3   }   private:   Singleton();                                                         //4   Singleton(const Singleton&);                             //5   Singleton& operator=(const Singleton&);            //6   ~Singleton();                                                       //7   }

解二在Instance中定義了一個Static的Singleton對象,來解決Instance中初始化的問題,也很順利的解決了定義Static成員對象帶來的問題。

請注意,解二在VC6中不能編譯通過,將有以下的錯誤:

error C2248: 'Singleton::~Singleton' : cannot access private member declared in class 'Singleton' e:\work\q\a.h(81) : see declaration of 'Singleton::~Singleton'

產(chǎn)生該問題的錯誤原因是什么呢(請仔細思考^_^)

原因在于在產(chǎn)生static Singleton對象后,編譯器會自動產(chǎn)生一個銷毀函數(shù)__DestroySingleton,然后調(diào)用atexit()注冊,在程序退出時執(zhí)行__DestroySingleton。但由于Singleton的析構(gòu)函數(shù)是private,所以會產(chǎn)生訪問錯誤。(應(yīng)該在以后的編譯器中修改了該BUG)

1.3      Singleton改進

讓Instance傳回引用(reference)。如果傳回指針,調(diào)用端有可能講它delete調(diào)。

1.4      Singleton注意之點

在上面的解法中,請注意對構(gòu)造函數(shù)和析構(gòu)函數(shù)的處理,有何好處(請自己理解,俺懶病又犯了)。

2         多線程

在解一中,如果我們運行在多線程的環(huán)境中,該方案是***的么,將會有什么后果呢?

后果就是會造成內(nèi)存泄漏,并且有可能前后獲取的Singleton對象不一樣(原因請自己思考,后面有解答)。

為了解決這個問題,將解一的Instance改為如下:

Singleton& Singleton::Instance(){   Lock(m_mutex);            //含義為獲取互斥量            //1   If( !m_pInstance ){                                          //2   m_pInstance = new Singleton; //3   }   UnLock(m_mutex);                                            //4   return *m_pInstance;                                     //5   }

此種方法將解決解一運行在多線程環(huán)境下內(nèi)存泄漏的問題,但帶來的結(jié)果是,當(dāng)m_mutex被鎖定時,其它試圖鎖定m_mutex的線程都將必須等等。并且每次執(zhí)行鎖操作其付出的代價極大,亦即是這種方案的解決辦法并不吸引人。

那么我們將上面的代碼改為如下方式:

Singleton& Singleton::Instance(){   If( !m_pInstance ){                                                      //1   Lock(m_mutex); //含義為獲取互斥量 //2   m_pInstance = new Singleton; //3   UnLock(m_mutex); //4   }   return *m_pInstance;                                                 //5   }

這樣修改的結(jié)果沒有問題了么?NO!!!!該方案帶來的結(jié)果同解一,原因也一樣,都將造成內(nèi)存泄漏。此時“雙檢測鎖定”模式就粉墨登場了。

由Doug Schmidt和Tim Harrison提出了“雙檢測鎖定”(Double-Checked Locking)模式來解決multithread singletons問題。

Singleton& Singleton::Instance(){   If( !m_pInstance ){                                                      //1   Lock(m_mutex); //含義為獲取互斥量 //2   If(!m_pInstance) //3   m_pInstance = new Singleton; //4   UnLock(m_mutex); //5   }   return *m_pInstance;                                                 //6   }

請看上面的第三句,這句話是不是具有化腐朽為神奇的力量啊 ^_^

上面的方案就***了么?;卮疬€是NO!!!(各位看官是否已經(jīng)郁悶了啊,這不是玩我啊?請耐心點,聽我細細到來^_^)

如果在RISC機器上編譯器有可能將上面的代碼優(yōu)化,在鎖定m_mutex前執(zhí)行第3句。這是完全有可能的,因為***句和第3句一樣,根據(jù)代碼優(yōu)化原則是可以這樣處理的。這樣一來,我們引以為自豪的“雙檢測鎖定”居然沒有起作用( L)

怎么辦?解決唄。怎么解決?簡單,我們在m_pInstance前面加一個修飾符就可以了。什么修飾符呢?……

àvolatile(簡單吧)

那么我們完整的解法如下:

/*解三*/   class Singleton   {   public:   static Singleton &Instance(){                            //1   if( !m_pInstatnce){ //2   Lock(m_mutex) //3   If( !m_pInstance ) //4   m_pInstance = new Singleton;//5   UnLock(m_mutex); //6   }   return *m_pInstance; //7   }   private:   static volatitle Singleton *m_pInstatnce;            //8   private:   Singleton();                                                         //9   Singleton(const Singleton&);                             //10   Singleton& operator=(const Singleton&);            //11   ~Singleton();                                                       //12   }   Singleton *Singleton:m_pInstatnce = NULL; //13

3         Singleton銷毀

在這里,我們就到了Singleton最簡單也最復(fù)雜的地方了。

為什么說它簡單?我們根本可以不理睬創(chuàng)建的對象m_pInstance的銷毀啊。因為雖然我們一直沒有將Singleton對象刪除,但不會造成內(nèi)存泄漏。為什么這樣說呢?因為只有當(dāng)你分配了累積行數(shù)據(jù)并丟失了對他的所有reference是,內(nèi)存泄漏才發(fā)生。而對Singleton并不屬于上面的情況,沒有累積性的東東,而且直到結(jié)束我們還有它的引用。在現(xiàn)代操作系統(tǒng)中,當(dāng)一個進程結(jié)束后,將自動將該進程所有內(nèi)存空間完全釋放。(可以參考《effective C++》條款10,里面講述了內(nèi)存泄漏)。

但有時泄漏還是存在的,那是什么呢?就是資源泄漏。比如說如果該Singleton對象管理的是網(wǎng)絡(luò)連接,OS互斥量,進程通信的handles等等。這時我們就必須考慮到Singleton的銷毀了。談到銷毀,那可是一個復(fù)雜的課題(兩天三夜也說不完^_^  開玩笑的啦,大家輕松一下嘛)。

我們需要在恰當(dāng)?shù)牡攸c,恰當(dāng)?shù)臅r機刪除Singleton對象,并且還要在恰當(dāng)?shù)臅r機創(chuàng)建或者重新創(chuàng)建Singleton對象。

在我們的“解二”中,在程序結(jié)束時會自動調(diào)用Singleton的析構(gòu)函數(shù),那么也將自動釋放所獲取的資源。在大多數(shù)情況下,它都能夠有效運作。那特殊情況是什么呢?

我們以KDL(keyboard,display,log)模型為例,其中K,D,L均使用Singleton模式。只要keyboard或者display出現(xiàn)異常,我們就必須調(diào)用log將其寫入日志中,否則log對象不應(yīng)該創(chuàng)建。對后面一條,我們的Singleton創(chuàng)建時就可以滿足。

在前面我們已經(jīng)說到,在產(chǎn)生一個對象時(非用new產(chǎn)生的對象),由編譯器自動調(diào)用了atexit(__DestroyObject)函數(shù)來實現(xiàn)該對象的析構(gòu)操作。而C++對象析構(gòu)是LIFO進行的,即先產(chǎn)生的對象后摧毀。

如果在一般情況下調(diào)用了log對象,然后開始銷毀對象。按照“后創(chuàng)建的先銷毀”原則:log對象將被銷毀,然后display對象開始銷毀。此時display在銷毀發(fā)現(xiàn)出現(xiàn)異常,于是調(diào)用log對象進行記錄。但事實上,log對象已經(jīng)被銷毀,那么調(diào)用log對象將產(chǎn)生不可預(yù)期的后果,此問題我們稱為Dead Reference。所以前面的解決方案不能解決目前我們遇到的問題。

Andrei Alexandrescu提出了解決方案,稱為Phoenix Singleton(取自鳳凰涅磐典故)

/*解四*/   class Singleton   {   public:   static Singleton &Instance(){                              if( !m_pInstatnce){   Lock(m_mutex)   If( !m_pInstance ){   if(m_destroyed)   OnDeadReference();   else   Create();   }   UnLock(m_mutex);   }   return *m_pInstance;   }   private:   static volatitle Singleton *m_pInstatnce;   static bool m_destroyed;   private:   Singleton();                                                           Singleton(const Singleton&);                               Singleton& operator=(const Singleton&);       ~Singleton(){   m_pInstance = 0;   m_destroyed = true;   }   static void Create(){   static Singleton sInstance;   m_pInstanace = &sInstance;   }   static void OnDeadReference(){   Create();   new (m_pInstance) Singleton;   atexit(KillPhoenixSingleton);   m_destroyed = false;   }   void KillPhoenixSingleton(){   m_pInstance->~Singleton();   }   }   Singleton *Singleton:m_pInstatnce = NULL;   bool m_destroyed =false;

請注意此處OnDeadReference()中所使用的new操作符的用法:是所謂的placement new操作,它并不分配內(nèi)存,而是在某個地址上構(gòu)造一個新對象。

這是解決Dead Reference方法之一。如果此時keyboard或者display對象也需要處理Dead Reference問題時,那么上面的OnDeadReference將被頻繁調(diào)用,效率將會很低。即該問題為:需要提供一種解決方案,用于處理對象的建立過程可以不按照“先創(chuàng)建會銷毀”的原則,而應(yīng)該為其指定一個銷毀順序。

聰明的Andrei Alexandrescu提出了一個“帶壽命的Singleton”解決方案。該方案的思想是:利用atexit()的特性;在每次創(chuàng)建一個對象后,將該對象放入到一個鏈表中(該鏈表是按照銷毀順序排訓(xùn)的),并同時調(diào)用atexit()注冊一個銷毀函數(shù);該銷毀函數(shù)從鏈表中獲取最需要銷毀的對象進行銷毀。

到此,關(guān)于“Singleton模式創(chuàng)建、多線程與銷毀的方法是什么”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

標(biāo)題名稱:Singleton模式創(chuàng)建、多線程與銷毀的方法是什么
標(biāo)題網(wǎng)址:http://m.newbst.com/article44/jegshe.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站建設(shè)外貿(mào)建站、營銷型網(wǎng)站建設(shè)、響應(yīng)式網(wǎng)站、虛擬主機

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

搜索引擎優(yōu)化