青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

#ant

The dreams in which I'm dying are the best I've ever had...

非完美C++ Singleton實現[2]

4.解決多線程問題
上一篇實現的Singleton只能在單線程環境中使用,在多線程環境中會出現很多問題,看Instance()實現代碼:
1?static?Singleton&?Instance()?{
2?????if?(0?==?_instance)?{?//1

3?????????_instance?=?new?Singleton();?//2
4?????????atexit(Destroy);
5?
????}
6?????return?*_instance;?//3

7?}
考慮如下情況:線程一調用Instance(),進入//1,0 == _instance 返回true,線程一于是進入//2。這時候線程一被掛起,線程二開始執行,線程二調用Instance(),進入//1,發現0 == _instance 仍然返回true,線程二于是也進入//2,線程二繼續執行到//3直到返回。這時候線程一被喚醒,繼續從//2開始執行,這將會覆蓋線程二創建的_instance,線程一繼續執行到//3直到返回...

解決方法很簡單,引入相關同步對象(synchronization object)就行了,例如在win32平臺下可以如下實現:
synobj.h
?1?#ifndef?SYNOBJ_H
?2?
#define?SYNOBJ_H
?3?

?4?#include?<windows.h>
?5?
?6?#define?CLASS_UNCOPYABLE(classname)?\
?7?????private
:?\
?8?????classname(const?classname&
);?\
?9?????classname&?operator=(const?classname&
);
10?

11?class?Mutex?{
12?
????CLASS_UNCOPYABLE(Mutex)
13?public
:
14?????Mutex()?:_cs()?{?InitializeCriticalSection(&
_cs);?}
15?????~Mutex()?{?DeleteCriticalSection(&
_cs);?}
16?????void?lock()?{?EnterCriticalSection(&
_cs);?}
17?????void?unlock()?{?LeaveCriticalSection(&
_cs);?}
18?private
:
19?
????CRITICAL_SECTION?_cs;
20?
};
21?

22?class?Lock?{
23?
????CLASS_UNCOPYABLE(Lock)
24?public
:
25?????explicit?Lock(Mutex&
?cs)?:_cs(cs)?{?_cs.lock();?}
26?????~
Lock()?{?_cs.unlock();?}
27?private
:
28?????Mutex&
?_cs;
29?
};
30?

31?#endif/*SYNOBJ_H*/

有了同步對象很容易就能夠寫出如下代碼:
singleton.h
?1?#ifndef?SINGLETON_H
?2?
#define?SINGLETON_H
?3?

?4?#include?"synobj.h"
?5?
?6?class?Singleton?{
?7?public
:
?8?????static?Singleton&?Instance()?{?//?Unique?point?of?access

?9?????????Lock?lock(_mutex);
10?????????if?(0?==
?_instance)?{
11?????????????_instance?=?new
?Singleton();
12?????????????atexit(Destroy);?//?Register?Destroy?function

13?????????}
14?????????return?*
_instance;
15?
????}
16?????void
?DoSomething(){}
17?private
:
18?????static?void?Destroy()?{?//?Destroy?the?only?instance

19?????????if?(?_instance?!=?0?)?{
20?
????????????delete?_instance;
21?????????????_instance?=?0
;
22?
????????}
23?
????}
24?????Singleton(){}?//?Prevent?clients?from?creating?a?new?Singleton

25?????~Singleton(){}?//?Prevent?clients?from?deleting?a?Singleton
26?????Singleton(const?Singleton&);?//?Prevent?clients?from?copying?a?Singleton
27?????Singleton&?operator=(const?Singleton&);
28?private
:
29?????static
?Mutex?_mutex;
30?????static?Singleton?*_instance;?//?The?one?and?only?instance

31?};
32?

33?#endif/*SINGLETON_H*/

singleton.cpp
1?#include?"singleton.h"
2?
3?Mutex?Singleton::_mutex;
4?Singleton*?Singleton::_instance?=?0;
現在的Singleton雖然多線程安全,性能卻受到了影響。從Instance()中可以看到,實際上僅僅當0 == _instance為true時才需要Lock。你很容易就寫出如下代碼:
1?static?Singleton&?Instance()?{
2?????if?(0?==
?_instance)?{
3?
????????Lock?lock(_mutex);
4?????????_instance?=?new
?Singleton();
5?
????????atexit(Destroy);
6?
????}
7?????return?*
_instance;
8?}
但是這樣還是會產生競爭條件(race condition),一種廣為人知的做法是使用所謂的Double-Checked Locking:
?1?static?Singleton&?Instance()?{
?2?????if?(0?==
?_instance)?{
?3?
????????Lock?lock(_mutex);
?4?????????if?(0?==
?_instance)?{
?5?????????????_instance?=?new
?Singleton();
?6?
????????????atexit(Destroy);
?7?
????????}
?8?
????}
?9?????return?*
_instance;
10?}
Double-Checked Locking機制看起來像是一個完美的解決方案,但是在某些條件下仍然不行。簡單的說,編譯器為了效率可能會重排指令的執行順序(compiler-based reorderings)??催@一行代碼:

_instance?=?new?Singleton();

在編譯器未優化的情況下順序如下:
1.new operator分配適當的內存;
2.在分配的內存上構造Singleton對象;
3.內存地址賦值給_instance。


但是當編譯器優化后執行順序可能如下:
1.new operator分配適當的內存;
2.內存地址賦值給_instance;
3.在分配的內存上構造Singleton對象。


當編譯器優化后,如果線程一執行到2后被掛起。線程二開始執行并發現0 == _instance為false,于是直接return,而這時Singleton對象可能還未構造完成,后果...

上面說的還只是單處理器的情況,在多處理器(multiprocessors)的情況下,超線程技術必然會混合執行指令,指令的執行順序更無法保障。關于Double-Checked Locking的更詳細的文章,請看:
The "Double-Checked Locking is Broken" Declaration

5.使用volatile關鍵字
為了說明問題,請先考慮如下代碼:
?1?class?MyThread?:?public?Thread?{
?2?public
:
?3?????virtual?void
?run()?{
?4?????????while?(!
_stopped)?{
?5?????????????//do?something

?6?????????}
?7?
????}
?8?????void
?stop()?{
?9?????????_stopped?=?true
;
10?
????}
11?private
:
12?
????bool?_stopped;
13?
};
14?

15?...
16?
17?MyThread?thread;
18?thread.start();
上面用thread.start()開啟了一個線程,該線程在while循環中檢測bool標記_stopped,看是否該繼續執行。如果想要結束這個線程,調用thread.stop()應該沒問題。但是需要注意的是編譯器很有可能對_stopped的存取進行優化。如果編譯器發現_stopped被頻繁存取(_stopped在while循環中),編譯器可能會考慮將_stopped緩存到寄存器中,以后_stopped將會直接從寄存器存取。這時候如果某個線程調用了thread.stop(),對_stopped的修改將不會反映到寄存器中,thread將會永遠循環下去...

為了防止編譯器優化,用volatile關鍵字就OK了,volatile跟const的用法幾乎一樣,能用const的地方也都能用volatile。對Singleton來說,修改如下兩處即可:
1?//singleton.h中
2?static?Singleton?*_instance;
3?//改為

4?static?Singleton?*?volatile?_instance;
5?

6?//singleton.cpp中
7?Singleton*?Singleton::_instance?=?0;
8?//改為

9?Singleton*?volatile?Singleton::_instance?=?0;


6.將Singleton泛化為模板
singleton.h
?1?#ifndef?SINGLETON_H
?2?
#define?SINGLETON_H
?3?

?4?#include?"synobj.h"
?5?
?6?template<class?T>
?7?class?Singleton?{
?8?
????CLASS_UNCOPYABLE(Singleton)
?9?public
:
10?????static?T&?Instance()?{?//?Unique?point?of?access

11?????????if?(0?==?_instance)?{
12?
????????????Lock?lock(_mutex);
13?????????????if?(0?==
?_instance)?{
14?????????????????_instance?=?new
?T();
15?
????????????????atexit(Destroy);
16?
????????????}
17?
????????}
18?????????return?*
_instance;
19?
????}
20?protected
:
21?
????Singleton(){}
22?????~
Singleton(){}
23?private
:
24?????static?void?Destroy()?{?//?Destroy?the?only?instance

25?????????if?(?_instance?!=?0?)?{
26?
????????????delete?_instance;
27?????????????_instance?=?0
;
28?
????????}
29?
????}
30?????static
?Mutex?_mutex;
31?????static?T?*?volatile?_instance;?//?The?one?and?only?instance

32?};
33?

34?template<class?T>
35?Mutex?Singleton<T>::_mutex;
36?

37?template<class?T>
38?T?*?volatile?Singleton<T>::_instance?=?0;
39?

40?#endif/*SINGLETON_H*/

測試代碼:
test.cpp
?1?#include?"singleton.h"
?2?
?3?class?A?:?public?Singleton<A>?{
?4?????friend?class?Singleton<A>
;
?5?protected
:
?6?
????A(){}
?7?????~
A(){}
?8?public
:
?9?????void
?DoSomething(){}
10?
};
11?

12?int?main()?{
13?

14?????A?&a?=?A::Instance();
15?
????a.DoSomething();
16?

17?????return?0;
18?}


7.Singleton的析構問題
到此Singleton已經算比較完善了,但是依然算不上完美,因為到現在只是解決了多線程問題,加入了模板支持,對于KDL problem(The Dead Reference Problem)依然沒法解決,可以說在實現Singleton模式時,最大的問題就是多個有依賴關系的Singleton的析構順序。雖然Modern C++ Design中給出了解決方案,但是Loki的實現太過復雜,在此就不詳細說明了,有興趣的可以看看Modern C++ Design,當然了,Loki庫中用策略模式實現的Singleton也很不錯!

posted on 2007-09-07 23:22 螞蟻終結者 閱讀(5116) 評論(13)  編輯 收藏 引用 所屬分類: Design Pattern

Feedback

# re: 非完美C++ Singleton實現[2] 2007-09-08 09:12 sneaker

"The Dead Reference Problem"確實是實現Singleton的首要問題  回復  更多評論   

# re: 非完美C++ Singleton實現[2] 2007-09-09 03:25 func

華麗的推演,“裱”成PDF收藏~期待下篇  回復  更多評論   

# re: 非完美C++ Singleton實現[2] 2007-09-10 11:14 ChenA

volatile也解決不了多線程的問題,詳情請看C++ and the Perils of Double-Checked Locking。
KDL的問題設計成不依賴不就行了,需要依賴關系的手動釋放,這是最簡單的辦法。  回復  更多評論   

# re: 非完美C++ Singleton實現[2] 2007-09-10 11:33 螞蟻終結者

@ChenA
thanks!  回復  更多評論   

# re: 非完美C++ Singleton實現[2] 2007-09-19 14:24 func

我的理解,volatile雖然不能解決多線程的很多問題,但這里的使用應該解決了問題.  回復  更多評論   

# re: 非完美C++ Singleton實現[2] 2007-10-09 14:33 fr3@K

已知 : global (static) instance 在 multithreading 下有啟始上的問題。
試問 : 如何用一個 global instance (mutex) 去確保另一個 global instance 的啟始正確?

請參考拙著 Is your Singleton Broken? (http://fsfoundry.org/codefreak/2006/05/05/is-your-singleton-broken/)  回復  更多評論   

# re: 非完美C++ Singleton實現[2] 2007-10-09 16:30 螞蟻終結者

@fr3@K
實際上multithreading的問題不在于mutex這里,一個好的設計會在main函數真正啟動后再調用Instance(),而這時候global object可以確保已經初始化,即在調用Instance()時可以保證mutex已經初始化。因此只要程序在真正進入main函數以前不調用Instance(),就不會有global instance的初始化問題。  回復  更多評論   

# re: 非完美C++ Singleton實現[2] 2007-10-09 16:32 螞蟻終結者

其實后來覺得多數情況下eager initialization要優于lazy initialization。
如經典的Meyer's Singleton以及Boost::singleton
  回復  更多評論   

# re: 非完美C++ Singleton實現[2] 2007-10-09 16:42 王博煒

強  回復  更多評論   

# re: 非完美C++ Singleton實現[2] 2007-10-09 21:00 fr3@K

@螞蟻終結者

我的考量多是站在 library writer (職業病) 的角度。
Library 常需要在程式一 load 上來就把 static (global) instance 啟始好. 總不好要求使用者進入 main() 才能使用.

希望你能把進入 main() 之后再呼叫 Instance() 這段加入你的文章里面, 以免誤導了讀者如我輩.

我是盡量避免 lazy initialization 的人, 尤其是在 static instance (singleton) 的創建上. Lazy initialization 的策略有可能造成譬如說一個 global logger 在某個對象的虛構函數內第一次被使用 (或許可能性很小, 但畢竟不能 100% 排除), 而我們又無法保證該 logger 肯定會被創建成功. 這樣是否代表我們必須在每個使用到 logger 的 destructor 內部做 try-and-catch? 等等問題...  回復  更多評論   

# re: 非完美C++ Singleton實現[2] 2007-10-10 09:06 螞蟻終結者

@fr3@K
謝謝你的建議。
不能從static code中調用Instance()確實是一種限制。我想應該可以通過某種類似Boost::singleton中的技巧來確保static object(mutex)在Instance()之前初始化。有時間了再把這段內容補上。  回復  更多評論   

# re: 非完美C++ Singleton實現[2] 2008-05-06 09:21 sodar

非常好的文章,學習了

可是遇到一個問題,如果我是在動態庫工程中使用這個Singleton,因為atexit不能用于DLL,這種實現是不是會有問題呢?  回復  更多評論   

# re: 非完美C++ Singleton實現[2] 2008-05-06 22:02 螞蟻終結者

@sodar
能說下在動態庫工程中使用Singleton的具體需求嗎?dll中用atexit注冊的函數在FreeLibrary的時候會被調用,可以保證Singleton安全析構。  回復  更多評論   

# re: 非完美C++ Singleton實現[2] 2012-05-28 08:26 SYBILRobbins

This is known that cash can make us autonomous. But what to do when somebody does not have money? The only one way is to try to get the <a href="http://goodfinance-blog.com/topics/business-loans">business loans</a> and financial loan.   回復  更多評論   


只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            一区二区三区四区五区在线| 久久综合成人精品亚洲另类欧美| 久久免费国产精品| 亚洲综合视频一区| 亚洲女人小视频在线观看| 一区二区三区四区国产| 一区二区免费在线视频| 亚洲小说欧美另类婷婷| 性做久久久久久| 久久一区二区三区四区五区| 噜噜噜躁狠狠躁狠狠精品视频| 免费成人黄色片| 欧美日韩三级电影在线| 国产精品一卡二卡| 好吊一区二区三区| 日韩一区二区免费高清| 性色av一区二区三区| 久久久亚洲高清| 亚洲七七久久综合桃花剧情介绍| 亚洲精品日日夜夜| 免费人成网站在线观看欧美高清| 亚洲另类春色国产| 久久精品亚洲国产奇米99| 欧美激情按摩| 国产目拍亚洲精品99久久精品| 黑人巨大精品欧美黑白配亚洲 | 你懂的国产精品永久在线| 亚洲国产成人精品女人久久久| 亚洲精品少妇| 久久国产婷婷国产香蕉| 久久精品九九| 欧美一区二区播放| 欧美黄色免费| 国产专区精品视频| 亚洲无吗在线| 亚洲国产视频一区| 久久噜噜噜精品国产亚洲综合| 欧美日韩中文字幕| 亚洲欧洲一区二区在线播放| 久久国产88| 亚洲调教视频在线观看| 欧美激情综合色| 好男人免费精品视频| 欧美亚洲在线视频| 亚洲精品少妇| 欧美另类视频| 91久久国产综合久久蜜月精品| 欧美日本精品一区二区三区| 国产综合自拍| 久久精品成人| 亚洲视频电影图片偷拍一区| 欧美国产丝袜视频| 亚洲电影视频在线| 久久视频一区二区| 午夜精品久久久久久久久久久久久| 欧美成人精品不卡视频在线观看| 狠狠久久婷婷| 免费看的黄色欧美网站| 久久久另类综合| 国内精品亚洲| 久久综合伊人77777尤物| 亚洲欧美日韩另类| 亚洲最新视频在线| 欧美日韩一区高清| 亚洲一区二区成人| 中日韩高清电影网| 国产精品久久久久秋霞鲁丝| 亚洲永久免费av| 亚洲在线观看视频| 国精品一区二区| 两个人的视频www国产精品| 久久精品视频在线看| 激情成人中文字幕| 牛牛国产精品| 欧美激情综合五月色丁香小说| 亚洲精品一区二区三区婷婷月| 国产一区二区三区久久悠悠色av| 欧美一级夜夜爽| 欧美在线免费播放| 在线日本高清免费不卡| 最新国产乱人伦偷精品免费网站| 欧美日韩一区二区在线观看| 性做久久久久久免费观看欧美| 欧美一级精品大片| 亚洲第一天堂av| 亚洲精品一区二区三| 国产精品日日做人人爱| 玖玖玖国产精品| 欧美精品久久久久久久久老牛影院| 宅男噜噜噜66一区二区66| 欧美日韩黄视频| 日韩一级大片在线| 午夜在线观看欧美| 日韩亚洲视频| 欧美一区国产二区| 一区二区激情| 久久久五月天| 亚洲欧美美女| 免费的成人av| 欧美一进一出视频| 欧美不卡一区| 久久久久久久网| 欧美视频在线一区二区三区| 久久蜜桃香蕉精品一区二区三区| 欧美人妖另类| 免费观看30秒视频久久| 国产精品狼人久久影院观看方式| 米奇777超碰欧美日韩亚洲| 欧美日韩亚洲一区三区| 另类综合日韩欧美亚洲| 国产精品一区三区| 99re6这里只有精品| 亚洲二区精品| 久久国产精品色婷婷| 亚洲欧美中文日韩在线| 欧美日韩成人网| 欧美韩日一区二区| 国产一区二区你懂的| 亚洲欧美日韩成人高清在线一区| 中国女人久久久| 欧美久久久久久久| 亚洲人午夜精品| 亚洲精品国产欧美| 久久综合中文字幕| 久久综合色天天久久综合图片| 国产精品欧美激情| 国产精品99久久久久久宅男 | 一区二区三区产品免费精品久久75 | 妖精视频成人观看www| 免费久久99精品国产自在现线| 久久av老司机精品网站导航| 国产精品高精视频免费| 99视频精品免费观看| 日韩视频―中文字幕| 欧美黄在线观看| 亚洲人体1000| 99在线精品免费视频九九视| 欧美精品在线一区二区| 亚洲激情在线观看| 一区二区三区精密机械公司| 欧美精品入口| 正在播放欧美视频| 午夜精品久久久久久久男人的天堂| 国产精品成人免费视频| 亚洲性夜色噜噜噜7777| 久久av一区二区三区| 国产一区二区三区四区三区四| 欧美一区在线直播| 模特精品裸拍一区| 亚洲精品一二三| 欧美午夜片在线观看| 性欧美暴力猛交69hd| 亚洲欧美激情在线视频| 久久久青草青青国产亚洲免观| 免费高清在线视频一区·| 亚洲国产精品电影| 欧美久久久久久久| 亚洲一级片在线看| 久久这里只有精品视频首页| 亚洲高清视频一区| 欧美日韩国产123区| 亚洲欧美视频一区| 欧美激情一区在线观看| 亚洲国产天堂久久综合| 99精品国产福利在线观看免费| 久久亚洲综合色| 欧美精品一区二区视频| 久久精品99国产精品| 欧美福利一区二区| 欧美成人国产| 欧美亚洲午夜视频在线观看| 欧美视频一二三区| 亚洲国产欧美一区二区三区丁香婷| 亚洲少妇一区| 一区二区欧美激情| 国产精品私人影院| 欧美国产精品v| 亚洲私人影院在线观看| 国产亚洲欧美日韩在线一区| 美女免费视频一区| 亚洲免费影视| 日韩一级精品视频在线观看| 久久女同精品一区二区| 一区二区三区鲁丝不卡| 尤妮丝一区二区裸体视频| 欧美日韩在线观看一区二区三区| 欧美在线欧美在线| 日韩视频不卡中文| 欧美成人午夜激情| 欧美中文字幕精品| 亚洲视频在线观看免费| 亚洲国产日韩在线| 国产亚洲一区精品| 国产精品免费观看在线| 欧美激情中文不卡| 鲁鲁狠狠狠7777一区二区| 欧美一区在线看| 亚洲图片欧美一区| 欧美一级大片在线免费观看| 一本久久综合亚洲鲁鲁五月天|