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

#ant

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

非完美C++ Singleton實(shí)現(xiàn)[2]

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

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

7?}
考慮如下情況:線程一調(diào)用Instance(),進(jìn)入//1,0 == _instance 返回true,線程一于是進(jìn)入//2。這時(shí)候線程一被掛起,線程二開始執(zhí)行,線程二調(diào)用Instance(),進(jìn)入//1,發(fā)現(xiàn)0 == _instance 仍然返回true,線程二于是也進(jìn)入//2,線程二繼續(xù)執(zhí)行到//3直到返回。這時(shí)候線程一被喚醒,繼續(xù)從//2開始執(zhí)行,這將會(huì)覆蓋線程二創(chuàng)建的_instance,線程一繼續(xù)執(zhí)行到//3直到返回...

解決方法很簡單,引入相關(guān)同步對(duì)象(synchronization object)就行了,例如在win32平臺(tái)下可以如下實(shí)現(xiàn):
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*/

有了同步對(duì)象很容易就能夠?qū)懗鋈缦麓a:
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;
現(xiàn)在的Singleton雖然多線程安全,性能卻受到了影響。從Instance()中可以看到,實(shí)際上僅僅當(dāng)0 == _instance為true時(shí)才需要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?}
但是這樣還是會(huì)產(chǎn)生競爭條件(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機(jī)制看起來像是一個(gè)完美的解決方案,但是在某些條件下仍然不行。簡單的說,編譯器為了效率可能會(huì)重排指令的執(zhí)行順序(compiler-based reorderings)。看這一行代碼:

_instance?=?new?Singleton();

在編譯器未優(yōu)化的情況下順序如下:
1.new operator分配適當(dāng)?shù)膬?nèi)存;
2.在分配的內(nèi)存上構(gòu)造Singleton對(duì)象;
3.內(nèi)存地址賦值給_instance。


但是當(dāng)編譯器優(yōu)化后執(zhí)行順序可能如下:
1.new operator分配適當(dāng)?shù)膬?nèi)存;
2.內(nèi)存地址賦值給_instance;
3.在分配的內(nèi)存上構(gòu)造Singleton對(duì)象。


當(dāng)編譯器優(yōu)化后,如果線程一執(zhí)行到2后被掛起。線程二開始執(zhí)行并發(fā)現(xiàn)0 == _instance為false,于是直接return,而這時(shí)Singleton對(duì)象可能還未構(gòu)造完成,后果...

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

5.使用volatile關(guān)鍵字
為了說明問題,請(qǐng)先考慮如下代碼:
?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()開啟了一個(gè)線程,該線程在while循環(huán)中檢測bool標(biāo)記_stopped,看是否該繼續(xù)執(zhí)行。如果想要結(jié)束這個(gè)線程,調(diào)用thread.stop()應(yīng)該沒問題。但是需要注意的是編譯器很有可能對(duì)_stopped的存取進(jìn)行優(yōu)化。如果編譯器發(fā)現(xiàn)_stopped被頻繁存取(_stopped在while循環(huán)中),編譯器可能會(huì)考慮將_stopped緩存到寄存器中,以后_stopped將會(huì)直接從寄存器存取。這時(shí)候如果某個(gè)線程調(diào)用了thread.stop(),對(duì)_stopped的修改將不會(huì)反映到寄存器中,thread將會(huì)永遠(yuǎn)循環(huán)下去...

為了防止編譯器優(yōu)化,用volatile關(guān)鍵字就OK了,volatile跟const的用法幾乎一樣,能用const的地方也都能用volatile。對(duì)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的析構(gòu)問題
到此Singleton已經(jīng)算比較完善了,但是依然算不上完美,因?yàn)榈浆F(xiàn)在只是解決了多線程問題,加入了模板支持,對(duì)于KDL problem(The Dead Reference Problem)依然沒法解決,可以說在實(shí)現(xiàn)Singleton模式時(shí),最大的問題就是多個(gè)有依賴關(guān)系的Singleton的析構(gòu)順序。雖然Modern C++ Design中給出了解決方案,但是Loki的實(shí)現(xiàn)太過復(fù)雜,在此就不詳細(xì)說明了,有興趣的可以看看Modern C++ Design,當(dāng)然了,Loki庫中用策略模式實(shí)現(xiàn)的Singleton也很不錯(cuò)!

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

Feedback

# re: 非完美C++ Singleton實(shí)現(xiàn)[2] 2007-09-08 09:12 sneaker

"The Dead Reference Problem"確實(shí)是實(shí)現(xiàn)Singleton的首要問題  回復(fù)  更多評(píng)論   

# re: 非完美C++ Singleton實(shí)現(xiàn)[2] 2007-09-09 03:25 func

華麗的推演,“裱”成PDF收藏~期待下篇  回復(fù)  更多評(píng)論   

# re: 非完美C++ Singleton實(shí)現(xiàn)[2] 2007-09-10 11:14 ChenA

volatile也解決不了多線程的問題,詳情請(qǐng)看C++ and the Perils of Double-Checked Locking。
KDL的問題設(shè)計(jì)成不依賴不就行了,需要依賴關(guān)系的手動(dòng)釋放,這是最簡單的辦法。  回復(fù)  更多評(píng)論   

# re: 非完美C++ Singleton實(shí)現(xiàn)[2] 2007-09-10 11:33 螞蟻終結(jié)者

@ChenA
thanks!  回復(fù)  更多評(píng)論   

# re: 非完美C++ Singleton實(shí)現(xiàn)[2] 2007-09-19 14:24 func

我的理解,volatile雖然不能解決多線程的很多問題,但這里的使用應(yīng)該解決了問題.  回復(fù)  更多評(píng)論   

# re: 非完美C++ Singleton實(shí)現(xiàn)[2] 2007-10-09 14:33 fr3@K

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

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

# re: 非完美C++ Singleton實(shí)現(xiàn)[2] 2007-10-09 16:30 螞蟻終結(jié)者

@fr3@K
實(shí)際上multithreading的問題不在于mutex這里,一個(gè)好的設(shè)計(jì)會(huì)在main函數(shù)真正啟動(dòng)后再調(diào)用Instance(),而這時(shí)候global object可以確保已經(jīng)初始化,即在調(diào)用Instance()時(shí)可以保證mutex已經(jīng)初始化。因此只要程序在真正進(jìn)入main函數(shù)以前不調(diào)用Instance(),就不會(huì)有g(shù)lobal instance的初始化問題。  回復(fù)  更多評(píng)論   

# re: 非完美C++ Singleton實(shí)現(xiàn)[2] 2007-10-09 16:32 螞蟻終結(jié)者

其實(shí)后來覺得多數(shù)情況下eager initialization要優(yōu)于lazy initialization。
如經(jīng)典的Meyer's Singleton以及Boost::singleton
  回復(fù)  更多評(píng)論   

# re: 非完美C++ Singleton實(shí)現(xiàn)[2] 2007-10-09 16:42 王博煒

強(qiáng)  回復(fù)  更多評(píng)論   

# re: 非完美C++ Singleton實(shí)現(xiàn)[2] 2007-10-09 21:00 fr3@K

@螞蟻終結(jié)者

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

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

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

# re: 非完美C++ Singleton實(shí)現(xiàn)[2] 2007-10-10 09:06 螞蟻終結(jié)者

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

# re: 非完美C++ Singleton實(shí)現(xiàn)[2] 2008-05-06 09:21 sodar

非常好的文章,學(xué)習(xí)了

可是遇到一個(gè)問題,如果我是在動(dòng)態(tài)庫工程中使用這個(gè)Singleton,因?yàn)閍texit不能用于DLL,這種實(shí)現(xiàn)是不是會(huì)有問題呢?  回復(fù)  更多評(píng)論   

# re: 非完美C++ Singleton實(shí)現(xiàn)[2] 2008-05-06 22:02 螞蟻終結(jié)者

@sodar
能說下在動(dòng)態(tài)庫工程中使用Singleton的具體需求嗎?dll中用atexit注冊(cè)的函數(shù)在FreeLibrary的時(shí)候會(huì)被調(diào)用,可以保證Singleton安全析構(gòu)。  回復(fù)  更多評(píng)論   

# re: 非完美C++ Singleton實(shí)現(xiàn)[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.   回復(fù)  更多評(píng)論   

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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亚洲导航| 另类亚洲自拍| 中文在线资源观看网站视频免费不卡 | 日韩视频亚洲视频| 亚洲免费成人av| 国产精品美女xx| 久热精品视频在线观看| 欧美高清在线观看| 欧美一级理论片| 久久久最新网址| 一本大道av伊人久久综合| 亚洲一区精彩视频| 在线观看成人av| 一区二区高清| 伊人精品成人久久综合软件| 亚洲黄色在线视频| 国产精品免费福利| 欧美成人免费网| 国产精品久久久久久久浪潮网站| 久久视频在线看| 欧美日韩福利在线观看| 久久精品1区| 欧美日本不卡视频| 久久久中精品2020中文| 欧美日韩hd| 美女脱光内衣内裤视频久久网站| 欧美日韩精品一区| 欧美福利一区二区三区| 国产老肥熟一区二区三区| 亚洲国产高清一区二区三区| 国产精品日韩一区二区| 欧美激情性爽国产精品17p| 国产乱子伦一区二区三区国色天香 | 欧美色视频一区| 欧美韩国在线| 国产综合自拍| 亚洲一区二区三区欧美 | 国产亚洲成精品久久| 亚洲精品视频在线看| 亚洲第一二三四五区| 亚洲欧美久久久| 亚洲一区二区三区在线| 免费成人高清在线视频| 欧美在线一级va免费观看| 欧美日韩在线免费视频| 亚洲国产视频一区| 在线观看中文字幕亚洲| 久久精品国产99| 欧美一区二区三区视频免费播放| 欧美日韩在线视频一区二区| 91久久线看在观草草青青| 亚洲成在人线av| 久久久久久久网| 另类国产ts人妖高潮视频| 国产一区二区三区自拍 | 亚洲视频1区| 亚洲免费中文字幕| 国产精品第十页| 亚洲第一网站| 久久久亚洲欧洲日产国码αv| 久久精品二区三区| 国产一区二区三区在线观看免费视频 | 亚洲综合成人婷婷小说| 久久大逼视频| 久久久91精品| 黑人极品videos精品欧美裸| 久久精品亚洲一区| 欧美成人小视频| 亚洲精品国产系列| 欧美日韩精选| 亚洲影视在线| 久久综合给合久久狠狠狠97色69| 黑人操亚洲美女惩罚| 免费不卡中文字幕视频| 亚洲精品之草原avav久久| 亚洲网站视频| 国产日韩欧美黄色| 久久久久久久综合色一本| 亚洲国产日韩在线| 亚洲午夜久久久久久久久电影院 | 国产精品地址| 欧美中文字幕久久| 亚洲高清色综合| 9l国产精品久久久久麻豆| 国产精品久久久久久久久久尿 | 久久免费精品日本久久中文字幕| 欧美福利视频网站| 亚洲天天影视| 禁久久精品乱码| 欧美日韩一区不卡| 欧美一区二区三区免费观看视频| 欧美不卡高清| 亚洲欧美日韩一区二区三区在线观看| 国产亚洲va综合人人澡精品| 欧美大片国产精品| 亚洲欧美激情视频| 91久久精品国产91久久| 欧美在线黄色| 一区二区精品在线| 韩国成人福利片在线播放| 欧美日韩一二区| 久久久久久综合网天天| 一本色道久久综合一区| 欧美ab在线视频| 欧美一区二区视频在线| 夜色激情一区二区| 国产自产v一区二区三区c| 欧美日韩中文字幕在线视频| 久久国产黑丝| 亚洲男女自偷自拍| 亚洲精品网址在线观看| 免费国产一区二区| 久久国产一区二区三区| 亚洲一区精品电影| 亚洲靠逼com| 亚洲第一在线| 国产一区三区三区| 国产精品夜色7777狼人| 欧美日本一道本在线视频| 蜜臀99久久精品久久久久久软件| 午夜视频精品| 亚洲欧美日韩人成在线播放| 99精品免费| 亚洲精品社区| 91久久久在线| 亚洲激情精品| 91久久精品日日躁夜夜躁国产| 亚洲欧美三级伦理| 老色批av在线精品| 久久精品午夜| 久久精品国产99精品国产亚洲性色| 亚洲欧美日韩一区二区| 亚洲伊人一本大道中文字幕| 一本一本久久a久久精品牛牛影视| 欧美国产一区在线| 亚洲国产成人精品视频| 欧美激情精品久久久| 欧美成人精品三级在线观看 | 亚洲图片在线观看| 亚洲视频精品在线| 亚洲一区二区高清视频| 亚洲综合三区| 久久精品99国产精品酒店日本| 久久精品视频免费播放| 久久亚洲综合色| 牛牛影视久久网| 亚洲国产精品黑人久久久| 亚洲日本中文字幕区| 一区二区三区不卡视频在线观看 | 欧美日韩在线观看视频| 国产精品成人免费| 国产三级精品三级| 娇妻被交换粗又大又硬视频欧美| 亚洲丰满少妇videoshd| 一区二区精品国产| 午夜精品999| 毛片精品免费在线观看| 亚洲国产一区在线| 一区二区三区波多野结衣在线观看| 亚洲一区三区电影在线观看| 久久精彩免费视频| 欧美韩日亚洲| 国产乱码精品一区二区三区忘忧草 | 欧美丰满高潮xxxx喷水动漫| 亚洲欧洲一区| 亚洲免费一在线| 裸体素人女欧美日韩| 欧美午夜在线观看| 精品999网站| 亚洲视频axxx| 久色成人在线| 99视频一区| 久久综合网hezyo| 国产精品国产三级国产aⅴ无密码| 好看的日韩av电影| 亚洲午夜久久久久久久久电影院 | 欧美一区二区三区在线| 蜜臀久久99精品久久久久久9| 夜夜嗨av色综合久久久综合网| 久久成人免费日本黄色| 欧美日韩999| 在线不卡视频| 欧美一区二区三区电影在线观看| 欧美国产视频一区二区| 亚洲欧美日韩视频二区| 欧美人与禽性xxxxx杂性| 韩国自拍一区| 欧美一区二区三区免费观看视频 | 欧美激情第1页| 午夜久久一区| 国产精品成人v| 99在线精品观看| 亚洲电影免费观看高清完整版| 先锋影音久久久| 亚洲激情国产精品| 亚洲免费av片|