﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-#ant-随笔分类-Design Pattern</title><link>http://www.cppblog.com/ant/category/5113.html</link><description>The dreams in which I'm dying are the best I've ever had...</description><language>zh-cn</language><lastBuildDate>Wed, 21 May 2008 06:41:35 GMT</lastBuildDate><pubDate>Wed, 21 May 2008 06:41:35 GMT</pubDate><ttl>60</ttl><item><title>非完美C++ Singleton实现[2]</title><link>http://www.cppblog.com/ant/archive/2007/09/07/31786.html</link><dc:creator>蚂蚁终结者</dc:creator><author>蚂蚁终结者</author><pubDate>Fri, 07 Sep 2007 15:22:00 GMT</pubDate><guid>http://www.cppblog.com/ant/archive/2007/09/07/31786.html</guid><wfw:comment>http://www.cppblog.com/ant/comments/31786.html</wfw:comment><comments>http://www.cppblog.com/ant/archive/2007/09/07/31786.html#Feedback</comments><slash:comments>13</slash:comments><wfw:commentRss>http://www.cppblog.com/ant/comments/commentRss/31786.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ant/services/trackbacks/31786.html</trackback:ping><description><![CDATA[
		<strong style="FONT-SIZE: 14pt; COLOR: #993366">4.解决多线程问题<br /></strong>上一篇实现的Singleton只能在单线程环境中使用，在多线程环境中会出现很多问题，看Instance()实现代码：<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><font face="Courier New"><span style="COLOR: #008080">1</span> <span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> Singleton</span><span style="COLOR: #000000">&amp;</span></font><font face="Courier New"><span style="COLOR: #000000"> Instance() {<br /></span><span style="COLOR: #008080">2</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> (</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">==</span><span style="COLOR: #000000"> _instance) { </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">1</span></font><span style="COLOR: #008000"><br /></span><font face="Courier New"><span style="COLOR: #008080">3</span> <span style="COLOR: #008000"></span><span style="COLOR: #000000">        _instance </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> Singleton(); </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">2</span></font><span style="COLOR: #008000"><br /></span><font face="Courier New"><span style="COLOR: #008080">4</span> <span style="COLOR: #008000"></span></font><font face="Courier New"><span style="COLOR: #000000">        atexit(Destroy);<br /></span><span style="COLOR: #008080">5</span> </font><font face="Courier New"><span style="COLOR: #000000">    }<br /></span><span style="COLOR: #008080">6</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">_instance; </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">3</span></font><span style="COLOR: #008000"><br /></span><font face="Courier New"><span style="COLOR: #008080">7</span> <span style="COLOR: #008000"></span><span style="COLOR: #000000">}</span></font></div>考虑如下情况：线程一调用Instance()，进入//1，0 == _instance 返回true，线程一于是进入//2。这时候线程一被挂起，线程二开始执行，线程二调用Instance()，进入//1，发现0 == _instance 仍然返回true，线程二于是也进入//2，线程二继续执行到//3直到返回。这时候线程一被唤醒，继续从//2开始执行，这将会覆盖线程二创建的_instance，线程一继续执行到//3直到返回...<br /><br />解决方法很简单，引入相关同步对象(synchronization object)就行了，例如在win32平台下可以如下实现：<br /><em style="COLOR: #333399">synobj.h<br /></em><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><font face="Courier New"><span style="COLOR: #008080"> 1</span> </font><font face="Courier New"><span style="COLOR: #000000">#ifndef SYNOBJ_H<br /></span><span style="COLOR: #008080"> 2</span> </font><font face="Courier New"><span style="COLOR: #000000">#define SYNOBJ_H<br /></span><span style="COLOR: #008080"> 3</span> </font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080"> 4</span> <span style="COLOR: #000000">#include </span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">windows.h</span><span style="COLOR: #000000">&gt;</span></font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080"> 5</span> </font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080"> 6</span> </font><font face="Courier New"><span style="COLOR: #000000">#define CLASS_UNCOPYABLE(classname) \<br /></span><span style="COLOR: #008080"> 7</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">private</span></font><font face="Courier New"><span style="COLOR: #000000">: \<br /></span><span style="COLOR: #008080"> 8</span> <span style="COLOR: #000000">    classname(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> classname</span><span style="COLOR: #000000">&amp;</span></font><font face="Courier New"><span style="COLOR: #000000">); \<br /></span><span style="COLOR: #008080"> 9</span> <span style="COLOR: #000000">    classname</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000"> operator</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> classname</span><span style="COLOR: #000000">&amp;</span></font><font face="Courier New"><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080">10</span> </font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080">11</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">class</span></font><font face="Courier New"><span style="COLOR: #000000"> Mutex {<br /></span><span style="COLOR: #008080">12</span> </font><font face="Courier New"><span style="COLOR: #000000">    CLASS_UNCOPYABLE(Mutex)<br /></span><span style="COLOR: #008080">13</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">public</span></font><font face="Courier New"><span style="COLOR: #000000">:<br /></span><span style="COLOR: #008080">14</span> <span style="COLOR: #000000">    Mutex() :_cs() { InitializeCriticalSection(</span><span style="COLOR: #000000">&amp;</span></font><font face="Courier New"><span style="COLOR: #000000">_cs); }<br /></span><span style="COLOR: #008080">15</span> <span style="COLOR: #000000">    </span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">Mutex() { DeleteCriticalSection(</span><span style="COLOR: #000000">&amp;</span></font><font face="Courier New"><span style="COLOR: #000000">_cs); }<br /></span><span style="COLOR: #008080">16</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> lock() { EnterCriticalSection(</span><span style="COLOR: #000000">&amp;</span></font><font face="Courier New"><span style="COLOR: #000000">_cs); }<br /></span><span style="COLOR: #008080">17</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> unlock() { LeaveCriticalSection(</span><span style="COLOR: #000000">&amp;</span></font><font face="Courier New"><span style="COLOR: #000000">_cs); }<br /></span><span style="COLOR: #008080">18</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">private</span></font><font face="Courier New"><span style="COLOR: #000000">:<br /></span><span style="COLOR: #008080">19</span> </font><font face="Courier New"><span style="COLOR: #000000">    CRITICAL_SECTION _cs;<br /></span><span style="COLOR: #008080">20</span> </font><font face="Courier New"><span style="COLOR: #000000">};<br /></span><span style="COLOR: #008080">21</span> </font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080">22</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">class</span></font><font face="Courier New"><span style="COLOR: #000000"> Lock {<br /></span><span style="COLOR: #008080">23</span> </font><font face="Courier New"><span style="COLOR: #000000">    CLASS_UNCOPYABLE(Lock)<br /></span><span style="COLOR: #008080">24</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">public</span></font><font face="Courier New"><span style="COLOR: #000000">:<br /></span><span style="COLOR: #008080">25</span> <span style="COLOR: #000000">    explicit Lock(Mutex</span><span style="COLOR: #000000">&amp;</span></font><font face="Courier New"><span style="COLOR: #000000"> cs) :_cs(cs) { _cs.lock(); }<br /></span><span style="COLOR: #008080">26</span> <span style="COLOR: #000000">    </span><span style="COLOR: #000000">~</span></font><font face="Courier New"><span style="COLOR: #000000">Lock() { _cs.unlock(); }<br /></span><span style="COLOR: #008080">27</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">private</span></font><font face="Courier New"><span style="COLOR: #000000">:<br /></span><span style="COLOR: #008080">28</span> <span style="COLOR: #000000">    Mutex</span><span style="COLOR: #000000">&amp;</span></font><font face="Courier New"><span style="COLOR: #000000"> _cs;<br /></span><span style="COLOR: #008080">29</span> </font><font face="Courier New"><span style="COLOR: #000000">};<br /></span><span style="COLOR: #008080">30</span> </font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080">31</span> <span style="COLOR: #000000">#endif</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">SYNOBJ_H</span><span style="COLOR: #008000">*/</span></font></div><br />有了同步对象很容易就能够写出如下代码：<br /><em style="COLOR: #333399">singleton.h<br /></em><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><font face="Courier New"><span style="COLOR: #008080"> 1</span> </font><font face="Courier New"><span style="COLOR: #000000">#ifndef SINGLETON_H<br /></span><span style="COLOR: #008080"> 2</span> </font><font face="Courier New"><span style="COLOR: #000000">#define SINGLETON_H<br /></span><span style="COLOR: #008080"> 3</span> </font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080"> 4</span> <span style="COLOR: #000000">#include </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">synobj.h</span><span style="COLOR: #000000">"</span></font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080"> 5</span> </font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080"> 6</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">class</span></font><font face="Courier New"><span style="COLOR: #000000"> Singleton {<br /></span><span style="COLOR: #008080"> 7</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">public</span></font><font face="Courier New"><span style="COLOR: #000000">:<br /></span><span style="COLOR: #008080"> 8</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> Singleton</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000"> Instance() { </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> Unique point of access</span></font><span style="COLOR: #008000"><br /></span><font face="Courier New"><span style="COLOR: #008080"> 9</span> <span style="COLOR: #008000"></span></font><font face="Courier New"><span style="COLOR: #000000">        Lock lock(_mutex);<br /></span><span style="COLOR: #008080">10</span> <span style="COLOR: #000000">        </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> (</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">==</span></font><font face="Courier New"><span style="COLOR: #000000"> _instance) {<br /></span><span style="COLOR: #008080">11</span> <span style="COLOR: #000000">            _instance </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span></font><font face="Courier New"><span style="COLOR: #000000"> Singleton();<br /></span><span style="COLOR: #008080">12</span> <span style="COLOR: #000000">            atexit(Destroy); </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> Register Destroy function</span></font><span style="COLOR: #008000"><br /></span><font face="Courier New"><span style="COLOR: #008080">13</span> <span style="COLOR: #008000"></span></font><font face="Courier New"><span style="COLOR: #000000">        }<br /></span><span style="COLOR: #008080">14</span> <span style="COLOR: #000000">        </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span></font><font face="Courier New"><span style="COLOR: #000000">_instance;<br /></span><span style="COLOR: #008080">15</span> </font><font face="Courier New"><span style="COLOR: #000000">    }<br /></span><span style="COLOR: #008080">16</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">void</span></font><font face="Courier New"><span style="COLOR: #000000"> DoSomething(){}<br /></span><span style="COLOR: #008080">17</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">private</span></font><font face="Courier New"><span style="COLOR: #000000">:<br /></span><span style="COLOR: #008080">18</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> Destroy() { </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> Destroy the only instance</span></font><span style="COLOR: #008000"><br /></span><font face="Courier New"><span style="COLOR: #008080">19</span> <span style="COLOR: #008000"></span><span style="COLOR: #000000">        </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( _instance </span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span></font><font face="Courier New"><span style="COLOR: #000000"> ) {<br /></span><span style="COLOR: #008080">20</span> </font><font face="Courier New"><span style="COLOR: #000000">            delete _instance;<br /></span><span style="COLOR: #008080">21</span> <span style="COLOR: #000000">            _instance </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span></font><font face="Courier New"><span style="COLOR: #000000">;<br /></span><span style="COLOR: #008080">22</span> </font><font face="Courier New"><span style="COLOR: #000000">        }<br /></span><span style="COLOR: #008080">23</span> </font><font face="Courier New"><span style="COLOR: #000000">    }<br /></span><span style="COLOR: #008080">24</span> <span style="COLOR: #000000">    Singleton(){} </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> Prevent clients from creating a new Singleton</span></font><span style="COLOR: #008000"><br /></span><font face="Courier New"><span style="COLOR: #008080">25</span> <span style="COLOR: #008000"></span><span style="COLOR: #000000">    </span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">Singleton(){} </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> Prevent clients from deleting a Singleton</span></font><span style="COLOR: #008000"><br /></span><font face="Courier New"><span style="COLOR: #008080">26</span> <span style="COLOR: #008000"></span><span style="COLOR: #000000">    Singleton(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> Singleton</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">); </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> Prevent clients from copying a Singleton</span></font><span style="COLOR: #008000"><br /></span><font face="Courier New"><span style="COLOR: #008080">27</span> <span style="COLOR: #008000"></span><span style="COLOR: #000000">    Singleton</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000"> operator</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> Singleton</span><span style="COLOR: #000000">&amp;</span></font><font face="Courier New"><span style="COLOR: #000000">);<br /></span><span style="COLOR: #008080">28</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">private</span></font><font face="Courier New"><span style="COLOR: #000000">:<br /></span><span style="COLOR: #008080">29</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">static</span></font><font face="Courier New"><span style="COLOR: #000000"> Mutex _mutex;<br /></span><span style="COLOR: #008080">30</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> Singleton </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">_instance; </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> The one and only instance</span></font><span style="COLOR: #008000"><br /></span><font face="Courier New"><span style="COLOR: #008080">31</span> <span style="COLOR: #008000"></span></font><font face="Courier New"><span style="COLOR: #000000">};<br /></span><span style="COLOR: #008080">32</span> </font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080">33</span> <span style="COLOR: #000000">#endif</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">SINGLETON_H</span><span style="COLOR: #008000">*/</span></font></div><br /><em style="COLOR: #333399">singleton.cpp<br /></em><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><font face="Courier New"><span style="COLOR: #008080">1</span> <span style="COLOR: #000000">#include </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">singleton.h</span><span style="COLOR: #000000">"</span></font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080">2</span> </font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080">3</span> </font><font face="Courier New"><span style="COLOR: #000000">Mutex Singleton::_mutex;<br /></span><span style="COLOR: #008080">4</span> <span style="COLOR: #000000">Singleton</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> Singleton::_instance </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;</span></font></div>现在的Singleton虽然多线程安全，性能却受到了影响。从Instance()中可以看到，实际上仅仅当0 == _instance为true时才需要Lock。你很容易就写出如下代码：<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><font face="Courier New"><span style="COLOR: #008080">1</span> <span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> Singleton</span><span style="COLOR: #000000">&amp;</span></font><font face="Courier New"><span style="COLOR: #000000"> Instance() {<br /></span><span style="COLOR: #008080">2</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> (</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">==</span></font><font face="Courier New"><span style="COLOR: #000000"> _instance) {<br /></span><span style="COLOR: #008080">3</span> </font><font face="Courier New"><span style="COLOR: #000000">        Lock lock(_mutex);<br /></span><span style="COLOR: #008080">4</span> <span style="COLOR: #000000">        _instance </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span></font><font face="Courier New"><span style="COLOR: #000000"> Singleton();<br /></span><span style="COLOR: #008080">5</span> </font><font face="Courier New"><span style="COLOR: #000000">        atexit(Destroy);<br /></span><span style="COLOR: #008080">6</span> </font><font face="Courier New"><span style="COLOR: #000000">    }<br /></span><span style="COLOR: #008080">7</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span></font><font face="Courier New"><span style="COLOR: #000000">_instance;<br /></span><span style="COLOR: #008080">8</span> <span style="COLOR: #000000">}</span></font></div>但是这样还是会产生竞争条件(race condition)，一种广为人知的做法是使用所谓的Double-Checked Locking：<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><font face="Courier New"><span style="COLOR: #008080"> 1</span> <span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> Singleton</span><span style="COLOR: #000000">&amp;</span></font><font face="Courier New"><span style="COLOR: #000000"> Instance() {<br /></span><span style="COLOR: #008080"> 2</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> (</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">==</span></font><font face="Courier New"><span style="COLOR: #000000"> _instance) {<br /></span><span style="COLOR: #008080"> 3</span> </font><font face="Courier New"><span style="COLOR: #000000">        Lock lock(_mutex);<br /></span><span style="COLOR: #008080"> 4</span> <span style="COLOR: #000000">        </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> (</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">==</span></font><font face="Courier New"><span style="COLOR: #000000"> _instance) {<br /></span><span style="COLOR: #008080"> 5</span> <span style="COLOR: #000000">            _instance </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span></font><font face="Courier New"><span style="COLOR: #000000"> Singleton();<br /></span><span style="COLOR: #008080"> 6</span> </font><font face="Courier New"><span style="COLOR: #000000">            atexit(Destroy);<br /></span><span style="COLOR: #008080"> 7</span> </font><font face="Courier New"><span style="COLOR: #000000">        }<br /></span><span style="COLOR: #008080"> 8</span> </font><font face="Courier New"><span style="COLOR: #000000">    }<br /></span><span style="COLOR: #008080"> 9</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span></font><font face="Courier New"><span style="COLOR: #000000">_instance;<br /></span><span style="COLOR: #008080">10</span> <span style="COLOR: #000000">}</span></font></div><span style="COLOR: #333399"><em>Double-Checked Locking</em></span>机制看起来像是一个完美的解决方案，但是在某些条件下仍然不行。简单的说，编译器为了效率可能会重排指令的执行顺序(<span style="COLOR: #333399"><em>compiler-based reorderings</em></span>)。看这一行代码：<br /><br /><font face="Courier New">_instance <span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span></font><span style="COLOR: #000000"><font face="Courier New"> Singleton();</font><br /><br />在编译器未优化的情况下顺序如下：<br /><span style="COLOR: #993366">1.new operator分配适当的内存；<br />2.在分配的内存上构造Singleton对象；<br />3.内存地址赋值给_instance。</span><br /><br />但是当编译器优化后执行顺序可能如下：<br /><span style="COLOR: #993366">1.new operator分配适当的内存；<br />2.内存地址赋值给_instance；<br />3.在分配的内存上构造Singleton对象。</span><br /><br />当编译器优化后，如果线程一执行到2后被挂起。线程二开始执行并发现0 == _instance为false，于是直接return，而这时Singleton对象可能还未构造完成，后果...<br /><br />上面说的还只是单处理器的情况，在多处理器(multiprocessors)的情况下，超线程技术必然会混合执行指令，指令的执行顺序更无法保障。关于<span style="COLOR: #333399"><em>Double-Checked Locking</em></span>的更详细的文章，请看：<br /><a href="http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html"><font color="#810081">The "Double-Checked Locking is Broken" Declaration</font></a><br /><br /><span style="COLOR: #993366"><strong style="FONT-SIZE: 14pt">5.使用volatile关键字<br /></strong></span>为了说明问题，请先考虑如下代码：<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><font face="Courier New"><span style="COLOR: #008080"> 1</span> <span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> MyThread : </span><span style="COLOR: #0000ff">public</span></font><font face="Courier New"><span style="COLOR: #000000"> Thread {<br /></span><span style="COLOR: #008080"> 2</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">public</span></font><font face="Courier New"><span style="COLOR: #000000">:<br /></span><span style="COLOR: #008080"> 3</span> <span style="COLOR: #000000">    virtual </span><span style="COLOR: #0000ff">void</span></font><font face="Courier New"><span style="COLOR: #000000"> run() {<br /></span><span style="COLOR: #008080"> 4</span> <span style="COLOR: #000000">        </span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000"> (</span><span style="COLOR: #000000">!</span></font><font face="Courier New"><span style="COLOR: #000000">_stopped) {<br /></span><span style="COLOR: #008080"> 5</span> <span style="COLOR: #000000">            </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">do something</span></font><span style="COLOR: #008000"><br /></span><font face="Courier New"><span style="COLOR: #008080"> 6</span> <span style="COLOR: #008000"></span></font><font face="Courier New"><span style="COLOR: #000000">        }<br /></span><span style="COLOR: #008080"> 7</span> </font><font face="Courier New"><span style="COLOR: #000000">    }<br /></span><span style="COLOR: #008080"> 8</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">void</span></font><font face="Courier New"><span style="COLOR: #000000"> stop() {<br /></span><span style="COLOR: #008080"> 9</span> <span style="COLOR: #000000">        _stopped </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">true</span></font><font face="Courier New"><span style="COLOR: #000000">;<br /></span><span style="COLOR: #008080">10</span> </font><font face="Courier New"><span style="COLOR: #000000">    }<br /></span><span style="COLOR: #008080">11</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">private</span></font><font face="Courier New"><span style="COLOR: #000000">:<br /></span><span style="COLOR: #008080">12</span> </font><font face="Courier New"><span style="COLOR: #000000">    bool _stopped;<br /></span><span style="COLOR: #008080">13</span> </font><font face="Courier New"><span style="COLOR: #000000">};<br /></span><span style="COLOR: #008080">14</span> </font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080">15</span> ...</font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080">16</span> </font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080">17</span> </font><font face="Courier New"><span style="COLOR: #000000">MyThread thread;<br /></span><span style="COLOR: #008080">18</span> <span style="COLOR: #000000">thread.start();</span></font></div></span>上面用thread.start()开启了一个线程，该线程在while循环中检测bool标记_stopped，看是否该继续执行。如果想要结束这个线程，调用thread.stop()应该没问题。但是需要注意的是编译器很有可能对_stopped的存取进行优化。如果编译器发现_stopped被频繁存取(_stopped在while循环中)，编译器可能会考虑将_stopped缓存到寄存器中，以后_stopped将会直接从寄存器存取。这时候如果某个线程调用了thread.stop()，对_stopped的修改将不会反映到寄存器中，thread将会永远循环下去...<br /><br />为了防止编译器优化，用volatile关键字就OK了，volatile跟const的用法几乎一样，能用const的地方也都能用volatile。对Singleton来说，修改如下两处即可：<br /><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><font face="Courier New"><span style="COLOR: #008080">1</span> <span style="COLOR: #008000">//</span><span style="COLOR: #008000">singleton.h中</span></font><span style="COLOR: #008000"><br /></span><font face="Courier New"><span style="COLOR: #008080">2</span> <span style="COLOR: #008000"></span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> Singleton </span><span style="COLOR: #000000">*</span></font><font face="Courier New"><span style="COLOR: #000000">_instance;<br /></span><span style="COLOR: #008080">3</span> <span style="COLOR: #000000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">改为</span></font><span style="COLOR: #008000"><br /></span><font face="Courier New"><span style="COLOR: #008080">4</span> <span style="COLOR: #008000"></span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> Singleton </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">volatile</span></font><font face="Courier New"><span style="COLOR: #000000"> _instance;<br /></span><span style="COLOR: #008080">5</span> </font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080">6</span> <span style="COLOR: #000000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">singleton.cpp中</span></font><span style="COLOR: #008000"><br /></span><font face="Courier New"><span style="COLOR: #008080">7</span> <span style="COLOR: #008000"></span><span style="COLOR: #000000">Singleton</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> Singleton::_instance </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span></font><font face="Courier New"><span style="COLOR: #000000">;<br /></span><span style="COLOR: #008080">8</span> <span style="COLOR: #000000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">改为</span></font><span style="COLOR: #008000"><br /></span><font face="Courier New"><span style="COLOR: #008080">9</span> <span style="COLOR: #008000"></span><span style="COLOR: #000000">Singleton</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">volatile</span><span style="COLOR: #000000"> Singleton::_instance </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;</span></font></div><br /><br /><strong style="FONT-SIZE: 14pt; COLOR: #993366">6.将Singleton泛化为模板<br /></strong><em style="COLOR: #333399">singleton.h<br /></em><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><font face="Courier New"><span style="COLOR: #008080"> 1</span> </font><font face="Courier New"><span style="COLOR: #000000">#ifndef SINGLETON_H<br /></span><span style="COLOR: #008080"> 2</span> </font><font face="Courier New"><span style="COLOR: #000000">#define SINGLETON_H<br /></span><span style="COLOR: #008080"> 3</span> </font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080"> 4</span> <span style="COLOR: #000000">#include </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">synobj.h</span><span style="COLOR: #000000">"</span></font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080"> 5</span> </font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080"> 6</span> <span style="COLOR: #000000">template</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> T</span><span style="COLOR: #000000">&gt;</span></font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080"> 7</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">class</span></font><font face="Courier New"><span style="COLOR: #000000"> Singleton {<br /></span><span style="COLOR: #008080"> 8</span> </font><font face="Courier New"><span style="COLOR: #000000">    CLASS_UNCOPYABLE(Singleton)<br /></span><span style="COLOR: #008080"> 9</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">public</span></font><font face="Courier New"><span style="COLOR: #000000">:<br /></span><span style="COLOR: #008080">10</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> T</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000"> Instance() { </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> Unique point of access</span></font><span style="COLOR: #008000"><br /></span><font face="Courier New"><span style="COLOR: #008080">11</span> <span style="COLOR: #008000"></span><span style="COLOR: #000000">        </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> (</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">==</span></font><font face="Courier New"><span style="COLOR: #000000"> _instance) {<br /></span><span style="COLOR: #008080">12</span> </font><font face="Courier New"><span style="COLOR: #000000">            Lock lock(_mutex);<br /></span><span style="COLOR: #008080">13</span> <span style="COLOR: #000000">            </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> (</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">==</span></font><font face="Courier New"><span style="COLOR: #000000"> _instance) {<br /></span><span style="COLOR: #008080">14</span> <span style="COLOR: #000000">                _instance </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span></font><font face="Courier New"><span style="COLOR: #000000"> T();<br /></span><span style="COLOR: #008080">15</span> </font><font face="Courier New"><span style="COLOR: #000000">                atexit(Destroy);<br /></span><span style="COLOR: #008080">16</span> </font><font face="Courier New"><span style="COLOR: #000000">            }<br /></span><span style="COLOR: #008080">17</span> </font><font face="Courier New"><span style="COLOR: #000000">        }<br /></span><span style="COLOR: #008080">18</span> <span style="COLOR: #000000">        </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span></font><font face="Courier New"><span style="COLOR: #000000">_instance;<br /></span><span style="COLOR: #008080">19</span> </font><font face="Courier New"><span style="COLOR: #000000">    }<br /></span><span style="COLOR: #008080">20</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">protected</span></font><font face="Courier New"><span style="COLOR: #000000">:<br /></span><span style="COLOR: #008080">21</span> </font><font face="Courier New"><span style="COLOR: #000000">    Singleton(){}<br /></span><span style="COLOR: #008080">22</span> <span style="COLOR: #000000">    </span><span style="COLOR: #000000">~</span></font><font face="Courier New"><span style="COLOR: #000000">Singleton(){}<br /></span><span style="COLOR: #008080">23</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">private</span></font><font face="Courier New"><span style="COLOR: #000000">:<br /></span><span style="COLOR: #008080">24</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> Destroy() { </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> Destroy the only instance</span></font><span style="COLOR: #008000"><br /></span><font face="Courier New"><span style="COLOR: #008080">25</span> <span style="COLOR: #008000"></span><span style="COLOR: #000000">        </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( _instance </span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span></font><font face="Courier New"><span style="COLOR: #000000"> ) {<br /></span><span style="COLOR: #008080">26</span> </font><font face="Courier New"><span style="COLOR: #000000">            delete _instance;<br /></span><span style="COLOR: #008080">27</span> <span style="COLOR: #000000">            _instance </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span></font><font face="Courier New"><span style="COLOR: #000000">;<br /></span><span style="COLOR: #008080">28</span> </font><font face="Courier New"><span style="COLOR: #000000">        }<br /></span><span style="COLOR: #008080">29</span> </font><font face="Courier New"><span style="COLOR: #000000">    }<br /></span><span style="COLOR: #008080">30</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">static</span></font><font face="Courier New"><span style="COLOR: #000000"> Mutex _mutex;<br /></span><span style="COLOR: #008080">31</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> T </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">volatile</span><span style="COLOR: #000000"> _instance; </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> The one and only instance</span></font><span style="COLOR: #008000"><br /></span><font face="Courier New"><span style="COLOR: #008080">32</span> <span style="COLOR: #008000"></span></font><font face="Courier New"><span style="COLOR: #000000">};<br /></span><span style="COLOR: #008080">33</span> </font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080">34</span> <span style="COLOR: #000000">template</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> T</span><span style="COLOR: #000000">&gt;</span></font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080">35</span> <span style="COLOR: #000000">Mutex Singleton</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">T</span><span style="COLOR: #000000">&gt;</span></font><font face="Courier New"><span style="COLOR: #000000">::_mutex;<br /></span><span style="COLOR: #008080">36</span> </font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080">37</span> <span style="COLOR: #000000">template</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> T</span><span style="COLOR: #000000">&gt;</span></font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080">38</span> <span style="COLOR: #000000">T </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">volatile</span><span style="COLOR: #000000"> Singleton</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">T</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">::_instance </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span></font><font face="Courier New"><span style="COLOR: #000000">;<br /></span><span style="COLOR: #008080">39</span> </font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080">40</span> <span style="COLOR: #000000">#endif</span><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">SINGLETON_H</span><span style="COLOR: #008000">*/</span></font></div><br />测试代码：<br /><span style="COLOR: #333399"><em>test.cpp<br /></em></span><div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><font face="Courier New"><span style="COLOR: #008080"> 1</span> <span style="COLOR: #000000">#include </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">singleton.h</span><span style="COLOR: #000000">"</span></font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080"> 2</span> </font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080"> 3</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> A : </span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000"> Singleton</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">A</span><span style="COLOR: #000000">&gt;</span></font><font face="Courier New"><span style="COLOR: #000000"> {<br /></span><span style="COLOR: #008080"> 4</span> <span style="COLOR: #000000">    friend </span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000"> Singleton</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">A</span><span style="COLOR: #000000">&gt;</span></font><font face="Courier New"><span style="COLOR: #000000">;<br /></span><span style="COLOR: #008080"> 5</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">protected</span></font><font face="Courier New"><span style="COLOR: #000000">:<br /></span><span style="COLOR: #008080"> 6</span> </font><font face="Courier New"><span style="COLOR: #000000">    A(){}<br /></span><span style="COLOR: #008080"> 7</span> <span style="COLOR: #000000">    </span><span style="COLOR: #000000">~</span></font><font face="Courier New"><span style="COLOR: #000000">A(){}<br /></span><span style="COLOR: #008080"> 8</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">public</span></font><font face="Courier New"><span style="COLOR: #000000">:<br /></span><span style="COLOR: #008080"> 9</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">void</span></font><font face="Courier New"><span style="COLOR: #000000"> DoSomething(){}<br /></span><span style="COLOR: #008080">10</span> </font><font face="Courier New"><span style="COLOR: #000000">};<br /></span><span style="COLOR: #008080">11</span> </font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080">12</span> <span style="COLOR: #000000"></span><span style="COLOR: #0000ff">int</span></font><font face="Courier New"><span style="COLOR: #000000"> main() {<br /></span><span style="COLOR: #008080">13</span> </font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080">14</span> <span style="COLOR: #000000">    A </span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">a </span><span style="COLOR: #000000">=</span></font><font face="Courier New"><span style="COLOR: #000000"> A::Instance();<br /></span><span style="COLOR: #008080">15</span> </font><font face="Courier New"><span style="COLOR: #000000">    a.DoSomething();<br /></span><span style="COLOR: #008080">16</span> </font><span style="COLOR: #000000"><br /></span><font face="Courier New"><span style="COLOR: #008080">17</span> <span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span></font><font face="Courier New"><span style="COLOR: #000000">;<br /></span><span style="COLOR: #008080">18</span> <span style="COLOR: #000000">}</span></font></div><p><br /><span style="COLOR: #993366"><strong style="FONT-SIZE: 14pt">7.Singleton的析构问题</strong></span><br />到此Singleton已经算比较完善了，但是依然算不上完美，因为到现在只是解决了多线程问题，加入了模板支持，对于<span style="COLOR: #333399"><em>KDL problem(The Dead Reference Problem)</em></span>依然没法解决，可以说在实现Singleton模式时，最大的问题就是<span style="COLOR: #993366">多个有依赖关系的Singleton的析构顺序</span>。虽然<em style="COLOR: #333399">Modern C++ Design</em>中给出了解决方案，但是<span style="COLOR: #333399"><em>Loki</em></span>的实现太过复杂，在此就不详细说明了，有兴趣的可以看看<span style="COLOR: #333399"><em>Modern C++ Design</em></span>，当然了，<span style="COLOR: #333399"><em>Loki</em></span>库中用策略模式实现的Singleton也很不错！<br /></p><img src ="http://www.cppblog.com/ant/aggbug/31786.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ant/" target="_blank">蚂蚁终结者</a> 2007-09-07 23:22 <a href="http://www.cppblog.com/ant/archive/2007/09/07/31786.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>非完美C++ Singleton实现[1]</title><link>http://www.cppblog.com/ant/archive/2007/09/07/31445.html</link><dc:creator>蚂蚁终结者</dc:creator><author>蚂蚁终结者</author><pubDate>Fri, 07 Sep 2007 06:49:00 GMT</pubDate><guid>http://www.cppblog.com/ant/archive/2007/09/07/31445.html</guid><wfw:comment>http://www.cppblog.com/ant/comments/31445.html</wfw:comment><comments>http://www.cppblog.com/ant/archive/2007/09/07/31445.html#Feedback</comments><slash:comments>12</slash:comments><wfw:commentRss>http://www.cppblog.com/ant/comments/commentRss/31445.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/ant/services/trackbacks/31445.html</trackback:ping><description><![CDATA[<p>Singleton模式是一种非常简单的设计模式，这种模式很常用也很容易被滥用。当你设计应用程序的时候，经常会遇到某些对象在整个程序的生命周期应该仅有一个实例的情况，比如<span style="COLOR: #333399"><em>File System，Graphic System，Logging Utility</em></span>，这时候就可以用到Singleton模式。Singleton模式在<span style="COLOR: #333399"><em>GOF</em></span>中描述如下：<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="COLOR: #993366"><em>&nbsp; Ensure a class only has one instance, and provide a global point of access to it.</em></span><br><br>Singleton模式的定义很简单，实现也有N多种，但是却很难找到一个称得上&#8220;完美&#8221;的。实现一个完美的Singleton比想象中要难的多，下面探索性的来实现一个非完美的。<br><br><span style="COLOR: #993366"><strong style="FONT-SIZE: 14pt">1.典型实现<br></strong></span>在C++中，Singleton模式的典型实现如下：<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><font face="Courier New"><span style="COLOR: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Header&nbsp;file&nbsp;Singleton.h</span></font> <span style="COLOR: #008000"><br></span><font face="Courier New"><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #0000ff">class</span></font> <font face="Courier New"><span style="COLOR: #000000">&nbsp;Singleton&nbsp;{<br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">public</span></font> <font face="Courier New"><span style="COLOR: #000000">:<br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;Singleton</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;Instance()&nbsp;{&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Unique&nbsp;point&nbsp;of&nbsp;access</span></font> <span style="COLOR: #008000"><br></span><font face="Courier New"><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">==</span></font> <font face="Courier New"><span style="COLOR: #000000">&nbsp;_instance)<br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_instance&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span></font> <font face="Courier New"><span style="COLOR: #000000">&nbsp;Singleton();<br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span></font> <font face="Courier New"><span style="COLOR: #000000">_instance;<br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;</font> <font face="Courier New"><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span></font> <font face="Courier New"><span style="COLOR: #000000">&nbsp;DoSomething();<br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">private</span></font> <font face="Courier New"><span style="COLOR: #000000">:<br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;Singleton();&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Prevent&nbsp;clients&nbsp;from&nbsp;creating&nbsp;a&nbsp;new&nbsp;Singleton</span></font> <span style="COLOR: #008000"><br></span><font face="Courier New"><span style="COLOR: #008080">12</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">Singleton();&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Prevent&nbsp;clients&nbsp;from&nbsp;deleting&nbsp;a&nbsp;Singleton</span></font> <span style="COLOR: #008000"><br></span><font face="Courier New"><span style="COLOR: #008080">13</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;Singleton(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;Singleton</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Prevent&nbsp;clients&nbsp;from&nbsp;copying&nbsp;a&nbsp;Singleton</span></font> <span style="COLOR: #008000"><br></span><font face="Courier New"><span style="COLOR: #008080">14</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;Singleton</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;operator</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;Singleton</span><span style="COLOR: #000000">&amp;</span></font> <font face="Courier New"><span style="COLOR: #000000">);<br></span><span style="COLOR: #008080">15</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">private</span></font> <font face="Courier New"><span style="COLOR: #000000">:<br></span><span style="COLOR: #008080">16</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;Singleton&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">_instance;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;The&nbsp;one&nbsp;and&nbsp;only&nbsp;instance</span></font> <span style="COLOR: #008000"><br></span><font face="Courier New"><span style="COLOR: #008080">17</span>&nbsp;<span style="COLOR: #008000"></span></font> <font face="Courier New"><span style="COLOR: #000000">};<br></span><span style="COLOR: #008080">18</span>&nbsp;</font> <span style="COLOR: #000000"><br></span><font face="Courier New"><span style="COLOR: #008080">19</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Implementation&nbsp;file&nbsp;Singleton.cpp</span></font> <span style="COLOR: #008000"><br></span><font face="Courier New"><span style="COLOR: #008080">20</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">Singleton</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;Singleton::_instance&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;</span></font> </div>
<p><br>通过将Singleton的构造函数设为private可以禁止客户代码直接创建Singleton对象，除此之外，Singleton的copy constructor和copy assignment operator都为private且仅有声明没有实现，禁止了客户代码拷贝Singleton对象。唯一可以创建Singleton对象的是Singleton自己的静态成员函数Instance，这样就在编译器保证了Singleton实例的唯一性。上面这些是在C++中实现Singleton模式最基本的要点。<br><br>Instance方法保证只有在第一次调用时才会生成Singleton对象，以后的调用只是简单返回唯一的已存在的实例。Instance方法实际上实现的是<span style="COLOR: #333399"><em>懒惰初始化(lazy initialize)，</em></span>如果程序中根本没有用到Singleton对象，也就根本不会产生Singleton的实例，这在Singleton对象很少使用且创建Singleton对象开销比较大的情况下特别有用。</p>
<p>客户代码现在可以这样使用Singleton：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><font face="Courier New"><span style="COLOR: #008080">1</span>&nbsp;<span style="COLOR: #000000">Singleton&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">s&nbsp;</span><span style="COLOR: #000000">=</span></font> <font face="Courier New"><span style="COLOR: #000000">&nbsp;Singleton::Instance();<br></span><span style="COLOR: #008080">2</span>&nbsp;<span style="COLOR: #000000">s.DoSomething();</span></font> </div>
<p><br>还需要说明的是Singleton的析构函数，析构函数也为private可以禁止客户写出如下代码。如果某个客户写出了如下代码，随后的对Singleton的访问就会导致为定义行为，因为Singleton对象已经不存在。<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><font face="Courier New"><span style="COLOR: #008080">1</span>&nbsp;<span style="COLOR: #000000">Singleton&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">p&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&amp;</span></font> <font face="Courier New"><span style="COLOR: #000000">Singleton::Instance();<br></span><span style="COLOR: #008080">2</span>&nbsp;<span style="COLOR: #000000">delete&nbsp;p;</span></font> </div>
<p><br><strong style="COLOR: #993366"><span style="FONT-SIZE: 14pt">2.引入smart pointer</span><br></strong>上面的实现算是一个好的实现吗？当然不是，或许连一个正确的实现都算不上。如果你想凑合，当然没问题，上面的代码大多数情况下可以工作的很好。也许你已经注意到了一些问题，比如说在上面的代码中只有new没有delete。是的，你说会发生memory leak对吧，其实memory leak都不是主要的问题，所有的现代操作系统在进程结束的时候都会对内存很好的进行回收。比memory leak更值得让人担忧的是resource leak，如果Singleton在构造函数中请求了某些资源：网络连接，文件句柄，数据库连接等。这些资源将得不到释放。<br><br>唯一修正resource leak的方法就是在程序结束的时候delete _instance。当然了，用smart pointer再好不过，在这里用auto_ptr就可以满足需要了(如果你还不知道smart_ptr是什么，花点时间熟悉C++标准库吧)，修改后的代码如下：<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><font face="Courier New"><span style="COLOR: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Header&nbsp;file&nbsp;Singleton.h</span></font> <span style="COLOR: #008000"><br></span><font face="Courier New"><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #0000ff">class</span></font> <font face="Courier New"><span style="COLOR: #000000">&nbsp;Singleton&nbsp;{<br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">public</span></font> <font face="Courier New"><span style="COLOR: #000000">:<br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;Singleton</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;Instance()&nbsp;{&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Unique&nbsp;point&nbsp;of&nbsp;access</span></font> <span style="COLOR: #008000"><br></span><font face="Courier New"><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">==</span></font> <font face="Courier New"><span style="COLOR: #000000">&nbsp;_instance.get())<br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_instance.reset(</span><span style="COLOR: #0000ff">new</span></font> <font face="Courier New"><span style="COLOR: #000000">&nbsp;Singleton());<br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span></font> <font face="Courier New"><span style="COLOR: #000000">(_instance.get());<br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;</font> <font face="Courier New"><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span></font> <font face="Courier New"><span style="COLOR: #000000">&nbsp;DoSomething(){}<br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">private</span></font> <font face="Courier New"><span style="COLOR: #000000">:<br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;Singleton(){}&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Prevent&nbsp;clients&nbsp;from&nbsp;creating&nbsp;a&nbsp;new&nbsp;Singleton</span></font> <span style="COLOR: #008000"><br></span><font face="Courier New"><span style="COLOR: #008080">12</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">Singleton(){}&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Prevent&nbsp;clients&nbsp;from&nbsp;deleting&nbsp;a&nbsp;Singleton</span></font> <span style="COLOR: #008000"><br></span><font face="Courier New"><span style="COLOR: #008080">13</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;Singleton(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;Singleton</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Prevent&nbsp;clients&nbsp;from&nbsp;copying&nbsp;a&nbsp;Singleton</span></font> <span style="COLOR: #008000"><br></span><font face="Courier New"><span style="COLOR: #008080">14</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;Singleton</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;operator</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;Singleton</span><span style="COLOR: #000000">&amp;</span></font> <font face="Courier New"><span style="COLOR: #000000">);<br></span><span style="COLOR: #008080">15</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">private</span></font> <font face="Courier New"><span style="COLOR: #000000">:<br></span><span style="COLOR: #008080">16</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;friend&nbsp;auto_ptr</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">Singleton</span><span style="COLOR: #000000">&gt;</span></font> <font face="Courier New"><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">17</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;auto_ptr</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">Singleton</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;_instance;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;The&nbsp;one&nbsp;and&nbsp;only&nbsp;instance</span></font> <span style="COLOR: #008000"><br></span><font face="Courier New"><span style="COLOR: #008080">18</span>&nbsp;<span style="COLOR: #008000"></span></font> <font face="Courier New"><span style="COLOR: #000000">};<br></span><span style="COLOR: #008080">19</span>&nbsp;</font> <span style="COLOR: #000000"><br></span><font face="Courier New"><span style="COLOR: #008080">20</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Implementation&nbsp;file&nbsp;Singleton.cpp</span></font> <span style="COLOR: #008000"><br></span><font face="Courier New"><span style="COLOR: #008080">21</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">auto_ptr</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">Singleton</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;Singleton::_instance;</span></font> </div>
<p><br><span style="COLOR: #993366"><strong style="FONT-SIZE: 14pt">3.用atexit替换smart pointer<br></strong></span>C++并没有规定不同<span style="COLOR: #333399"><em>编译单元(translation unit，简单说就是一个可编译的cpp文件)</em></span>中static对象的初始化顺序。如果一个程序中有多个Singleton对象，那么这些Singleton对象的析构顺序也将是任意的。很显然，当多个Singleton对象有依赖关系时，smart pointer根本无法保证Singleton的析构顺序。<br><br>msdn中对atexit描述如下：</p>
<p>The <strong>atexit</strong> function is passed the address of a function (<span class=parameter>func</span>) to be called when the program terminates normally. Successive calls to <strong>atexit</strong> create a register of functions that are executed in last-in, first-out (LIFO) order. The functions passed to <strong>atexit</strong> cannot take parameters. <strong>atexit</strong>&nbsp; use the heap to hold the register of functions. Thus, the number of functions that can be registered is limited only by heap memory.<br><br>需要说明的是atexit并不比smart pointer好多少，LIFO的保证对于有复杂依赖关系的多个Singleton依然束手无力，但是用atexit替换smart pointer却是必须的，它是设计完美Singleton的基础。<br><br><br><span style="COLOR: #993366">#如果你疑惑atexit为什么还是不行，请考虑下面的情况：</span><br>NOTE：下面的情况在<em>Modern C++ Design</em>中叫做<em style="COLOR: #333399">KDL(Keyboard,Display,Log)problem</em>。<br><br>某个程序中使用了如下3个Singleton：<span style="COLOR: #333399">Keyboard</span>，<span style="COLOR: #333399">Display</span>，<span style="COLOR: #333399">Log</span>。<span style="COLOR: #333399">Keyboard</span>和<span style="COLOR: #333399">Display</span>分别对应于计算机的键盘和显示器，<span style="COLOR: #333399">Log</span>用来记录错误信息。假设当<span style="COLOR: #333399">Keyboard</span>和<span style="COLOR: #333399">Display</span>的构造函数和析构函数出现错误时会调用<span style="COLOR: #333399">Log</span>记录错误信息，并且构造和析构导致的任何错误都会终止程序。<br><br>在程序启动时，如果<span style="COLOR: #333399">Keyboard</span>构造成功，<span style="COLOR: #333399">Display</span>构造失败，很显然在<span style="COLOR: #333399">Display</span>的构造函数中将会构造<span style="COLOR: #333399">Log</span>而且失败信息会被<span style="COLOR: #333399">Log</span>记录，根据假设这时候程序准备退出，atexit注册的函数将会按LIFO的顺序被调用。因为<span style="COLOR: #333399">Keyboard</span>先于<span style="COLOR: #333399">Log</span>构造，所以<span style="COLOR: #333399">Log</span>先于<span style="COLOR: #333399">Keyboard</span>析构，但是当由于某种原因<span style="COLOR: #333399">Keyboard</span>在析构时失败，想要调用<span style="COLOR: #333399">Log</span>记录错误信息时，<span style="COLOR: #333399">Log</span>早已被销毁，则Log::Instance()将会导致未定义行为。<br></p>
<p><span style="COLOR: #993366">#atexit的严重问题：</span> <br>从上面的例子可以看出，atexit和smart pointer相比仅仅是有LIFO的保证而已，这样的保证貌似也不怎么有效，因为atexit跟smart pointer一样也无法解决<em style="COLOR: #333399">KDL probleam</em>。<br><br>atexit由于LIFO带来了另外的问题，看下面的代码：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><font face="Courier New"><span style="COLOR: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">cstdlib</span><span style="COLOR: #000000">&gt;</span></font> <span style="COLOR: #000000"><br></span><font face="Courier New"><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">void</span></font> <font face="Courier New"><span style="COLOR: #000000">&nbsp;Bar()&nbsp;{<br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;</font> <font face="Courier New"><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;...<br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;</font> <font face="Courier New"><span style="COLOR: #000000">}<br></span><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">void</span></font> <font face="Courier New"><span style="COLOR: #000000">&nbsp;Foo()&nbsp;{<br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;</font> <font face="Courier New"><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;std::atexit(Bar);<br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;</font> <font face="Courier New"><span style="COLOR: #000000">}<br></span><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">int</span></font> <font face="Courier New"><span style="COLOR: #000000">&nbsp;main()&nbsp;{<br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;</font> <font face="Courier New"><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;std::atexit(Foo);<br></span><span style="COLOR: #008080">10</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span></font> <font face="Courier New"><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #000000">}</span></font> </div>
<p>上面的小段代码用atexit注册了Foo，Foo调用了std::atexit(Bar)。当程序退出时，根据atexit的LIFO保证，Bar在Foo之后注册，因此Bar应该在Foo之前调用，但是当Bar注册的时候Foo已经调用了，Bar根本就没有机会能够在Foo之前调用。这明显自相矛盾对吧，没办法，C++标准好像忽视了这一点，因此如果类似代码被调用，肯定不会有什么好的结果，好一点是resource leak，差一点估计程序就崩溃了！！！<br><br>atexit的这个问题跟Singleton有关系吗？当然有，如果在一个Singleton的析构函数中调用atexit就会出现上述问题。即在<span style="COLOR: #333399"><em>KDL problem</em></span>中，如果<span style="COLOR: #333399">Keyboard</span>和<span style="COLOR: #333399">Display</span>都构造成功，当<span style="COLOR: #333399">Keyboard</span>或<span style="COLOR: #333399">Display</span>任意一个析构失败时，<span style="COLOR: #333399">Keyboard</span>或<span style="COLOR: #333399">Display</span>在析构函数中会构造<span style="COLOR: #333399">Log</span>，<span style="COLOR: #333399">Log</span>的构造函数会间接调用atexit。oops!!!，可怕的未定义行为。<br><br>看到这里你一定对atexit相当失望，貌似它带来的好处多于坏处。但是请你相信，如果适当设计，atexit在后面的Singleton改造中会起到很重要的作用。<br><br>用atexit后的代码：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><font face="Courier New"><span style="COLOR: #008080">&nbsp;1</span>&nbsp;<span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Header&nbsp;file&nbsp;Singleton.h</span></font> <span style="COLOR: #008000"><br></span><font face="Courier New"><span style="COLOR: #008080">&nbsp;2</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #0000ff">class</span></font> <font face="Courier New"><span style="COLOR: #000000">&nbsp;Singleton&nbsp;{<br></span><span style="COLOR: #008080">&nbsp;3</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">public</span></font> <font face="Courier New"><span style="COLOR: #000000">:<br></span><span style="COLOR: #008080">&nbsp;4</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;Singleton</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;Instance()&nbsp;{&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Unique&nbsp;point&nbsp;of&nbsp;access</span></font> <span style="COLOR: #008000"><br></span><font face="Courier New"><span style="COLOR: #008080">&nbsp;5</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">==</span></font> <font face="Courier New"><span style="COLOR: #000000">&nbsp;_instance)&nbsp;{<br></span><span style="COLOR: #008080">&nbsp;6</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_instance&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span></font> <font face="Courier New"><span style="COLOR: #000000">&nbsp;Singleton();<br></span><span style="COLOR: #008080">&nbsp;7</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;atexit(Destroy);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Register&nbsp;Destroy&nbsp;function</span></font> <span style="COLOR: #008000"><br></span><font face="Courier New"><span style="COLOR: #008080">&nbsp;8</span>&nbsp;<span style="COLOR: #008000"></span></font> <font face="Courier New"><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">&nbsp;9</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span></font> <font face="Courier New"><span style="COLOR: #000000">_instance;<br></span><span style="COLOR: #008080">10</span>&nbsp;</font> <font face="Courier New"><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">11</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span></font> <font face="Courier New"><span style="COLOR: #000000">&nbsp;DoSomething(){}<br></span><span style="COLOR: #008080">12</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">private</span></font> <font face="Courier New"><span style="COLOR: #000000">:<br></span><span style="COLOR: #008080">13</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;Destroy()&nbsp;{&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Destroy&nbsp;the&nbsp;only&nbsp;instance</span></font> <span style="COLOR: #008000"><br></span><font face="Courier New"><span style="COLOR: #008080">14</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(&nbsp;_instance&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span></font> <font face="Courier New"><span style="COLOR: #000000">&nbsp;)&nbsp;{<br></span><span style="COLOR: #008080">15</span>&nbsp;</font> <font face="Courier New"><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;_instance;<br></span><span style="COLOR: #008080">16</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_instance&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span></font> <font face="Courier New"><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">17</span>&nbsp;</font> <font face="Courier New"><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">18</span>&nbsp;</font> <font face="Courier New"><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="COLOR: #008080">19</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;Singleton(){}&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Prevent&nbsp;clients&nbsp;from&nbsp;creating&nbsp;a&nbsp;new&nbsp;Singleton</span></font> <span style="COLOR: #008000"><br></span><font face="Courier New"><span style="COLOR: #008080">20</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">Singleton(){}&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Prevent&nbsp;clients&nbsp;from&nbsp;deleting&nbsp;a&nbsp;Singleton</span></font> <span style="COLOR: #008000"><br></span><font face="Courier New"><span style="COLOR: #008080">21</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;Singleton(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;Singleton</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Prevent&nbsp;clients&nbsp;from&nbsp;copying&nbsp;a&nbsp;Singleton</span></font> <span style="COLOR: #008000"><br></span><font face="Courier New"><span style="COLOR: #008080">22</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;Singleton</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">&nbsp;operator</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;Singleton</span><span style="COLOR: #000000">&amp;</span></font> <font face="Courier New"><span style="COLOR: #000000">);<br></span><span style="COLOR: #008080">23</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #0000ff">private</span></font> <font face="Courier New"><span style="COLOR: #000000">:<br></span><span style="COLOR: #008080">24</span>&nbsp;<span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;Singleton&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">_instance;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;The&nbsp;one&nbsp;and&nbsp;only&nbsp;instance</span></font> <span style="COLOR: #008000"><br></span><font face="Courier New"><span style="COLOR: #008080">25</span>&nbsp;<span style="COLOR: #008000"></span></font> <font face="Courier New"><span style="COLOR: #000000">};<br></span><span style="COLOR: #008080">26</span>&nbsp;</font> <span style="COLOR: #000000"><br></span><font face="Courier New"><span style="COLOR: #008080">27</span>&nbsp;<span style="COLOR: #000000"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;Implementation&nbsp;file&nbsp;Singleton.cpp</span></font> <span style="COLOR: #008000"><br></span><font face="Courier New"><span style="COLOR: #008080">28</span>&nbsp;<span style="COLOR: #008000"></span><span style="COLOR: #000000">Singleton</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;Singleton::_instance&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;</span></font> </div>
<br>你有没有仔细考虑过Destroy中的_instance = 0;这一行代码，上述代码实际上实现的是<em style="COLOR: #333399">不死鸟模式(The Phoenix Singleton)，</em>所谓不死鸟，就跟一辉一样可以死而复生。上面的代码可以解决本文最早提出的<em style="COLOR: #333399">KDL problem</em>，即如果<span style="COLOR: #333399">Keyboard</span>析构失败，虽然<span style="COLOR: #333399">Log</span>已经析构，但是由于Destroy中的_instance = 0;这一行代码，Log::Instance()将会创建一个新的<span style="COLOR: #333399">Log</span>对象，程序将会表现良好。当然了，<span style="COLOR: #993366">Phoenix Singleton</span>仅能用于无状态的Singleton，如果<span style="COLOR: #333399">Log</span>需要保存某些状态，<span style="COLOR: #993366">Phoenix Singleton</span>也不会带来任何好处。你当然可以用某些方法维持<span style="COLOR: #993366">Phoenix Singleton</span>的状态，但是在做之前先想想看是否值得，维持状态可能会使Singleton变得特别复杂。<br><br>上面的<span style="COLOR: #993366">Phoenix Singleton</span>已经可以满足大部分需要，如果你的Singleton没有涉及到多线程，多个Singleton之间也没有依赖关系，你大可以放心使用。但是如果你用到多线程，或者你的Singleton关系如<span style="COLOR: #333399"><em>KDL</em></span>般复杂，或者你觉得对每一个Singleton都敲同样的代码让你厌烦。在后面几篇会有一个<span style="COLOR: #993366">多线程安全</span>的，能够<span style="COLOR: #993366">解决多个Singleton依赖关系</span>的，<span style="COLOR: #993366">基于模板</span>的Singleton实现。<br>
<img src ="http://www.cppblog.com/ant/aggbug/31445.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/ant/" target="_blank">蚂蚁终结者</a> 2007-09-07 14:49 <a href="http://www.cppblog.com/ant/archive/2007/09/07/31445.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>