-
Notifications
You must be signed in to change notification settings - Fork 3
/
singularity.htm
369 lines (304 loc) · 16.5 KB
/
singularity.htm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
<html><head><meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Boost.Singularity (Proposed)</title>
<link rel="stylesheet" href="./boostbook.css" type="text/css">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<div class="titlepage"><div>
<div><h2 class="title">
<a name="singularity"></a>Boost.Singularity (Proposed)
</h2></div>
<div><div class="author"><h3 class="author">
<span class="firstname">Ben</span> <span class="surname">Robinson</span>, <span class="degree">Ph.D.</span>
</h3></div></div>
<div><p class="copyright">Copyright © 2011 Ben Robinson, Ph.D.</p></div>
<div><div class="legalnotice">
<a name="id1268168"></a><p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_blank">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></div>
</div></div>
<div class="toc">
<p><b>Table of Contents</b></p>
<dl>
<dt><span class="section"><a href="#singularity.introduction">Introduction</a></span></dt>
<dt><span class="section"><a href="#singularity.justification">Justification</a></span></dt>
<dt><span class="section"><a href="#singularity.tutorial">Tutorial</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="#singularity.factory">Usage as a Factory</a></span></dt>
<dt><span class="section"><a href="#singularity.baseclass">Usage as a Base Class</a></span></dt>
<dt><span class="section"><a href="#singularity.globalaccess">Enabling Global Access</a></span></dt>
<dt><span class="section"><a href="#singularity.threadsafety">Enabling Thread Safety</a></span></dt>
</dl></dd>
<dt><span class="section"><a href="#singularity.limitations">Limitations</a></span></dt>
<dt><span class="section"><a href="#singularity.customization">Customization</a></span></dt>
<dd><dl>
<dt><span class="section"><a href="#singularity.threadingpolicy">Threading Policy</a></span></dt>
</dl></dd>
<dt><span class="section"><a href="#singularity.references">References</a></span></dt>
</dl>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="singularity.introduction"></a><a class="link" href="#singularity.introduction" title="Introduction">Introduction</a>
</h2></div></div></div>
<p>
The Singularity Design Pattern allows you to restrict any class to a single instance. Singularity gives you direct control over the lifetime of the object, is not a global object, does not limit you to a single constructor for the object, and is easily unit tested.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="singularity.justification"></a><a class="link" href="#singularity.justification" title="Justification">Justification</a>
</h2></div></div></div>
<p>
The ability to restrict a class to a single instance is an important technique. While the commonly used Singleton Design Pattern achieves the desired goal, it introduces four undesirable limitations, namely:
</p>
<ol>
<li>Lifetime: Singleton introduces numerous lifetime management complexities. The undefined destruction order of multiple singletons is just one example.</li>
<li>Scope: Singletons are global. It is good practice to prefer non-globals wherever possible. Object accessibility should be orthogonal to restrictions on the number of instances.</li>
<li>Unit Testing: Singletons exist for the duration of program execution, which creates an order dependence between independent unit tests. Also as a global, they are a difficult to replace dependency.</li>
<li>Initialization: Singletons typically restricts the class to the default constructor. This makes Singleton difficult for classes which require non-default constructors.</li>
</ol>
<p>
Like Singleton, Singularity restricts a class to a single instance. However Singularity does not suffer from lifetime, scoping, initialization and unit testing problems. The following are the advantages of Singularity over Singleton:
</p>
<ol>
<li>Lifetime: The lifetime of the single object is bounded by calls to create() and destroy(). This lifetime is managed similiarly to objects bounded by calls to new() and delete().</li>
<li>Scope: Singularity is not a global by default. If global access is required, then a globally accessible get_global() function can be enabled upon creation of the instance.</li>
<li>Unit Testing: Singularities can be created before each unit test and explicity destroyed afterwords. Therefore each unit test runs completely independent from the state of the other tests.</li>
<li>Initialization: Singularities of objects can be created using any available constructor for that object.</li>
</ol>
<p>
An excellent article on <a class="link" href="http://blogs.msdn.com/b/scottdensmore/archive/2004/05/25/140827.aspx">Why Singletons are Evil</a> is given by Scott Densmore. Singularity neatly solves each described weakness.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="singularity.tutorial"></a><a class="link" href="#singularity.tutorial" title="Tutorial">Tutorial</a>
</h2></div></div></div>
<p>
To use Singularity, either as a factory or a base class, the class which is to be singular must make all constructors private, and friend the singularity class. A macro is provided to simplify the friend statement:
</p>
<pre class="programlisting">
<span class="preprocessor">#define</span> FRIEND_CLASS_SINGULARITY \
<span class="keyword">template</span> <<span class="keyword">class</span> T, <span class="keyword">template</span> <<span class="keyword">class</span> T> <span class="keyword">class</span> M> <span class="keyword">friend</span> <span class="keyword">class</span> singularity
</pre>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title" style="clear: both">
<a name="singularity.factory"></a><a class="link" href="#singularity.factory" title="Usage as a Factory">Usage as a Factory</a>
</h3></div></div></div>
<p>
Usage as a factory is shown as follows:
</p>
<pre class="programlisting">
<span class="preprocessor">#include</span> <singularity.hpp>
<span class="keyword">using</span> ::boost::singularity;
<span class="comment">// This is the class which will be singularized.</span>
<span class="comment">// Notice the private constructors and friend statement.</span>
<span class="keyword">class</span> Horizon
{
<span class="keyword">private</span>:
Horizon() {}
Horizon(int arg0) {}
...
FRIEND_CLASS_SINGULARITY;
};
int main()
{
<span class="comment">// Create using the default constructor.</span>
Horizon & firstHorizon = singularity<Horizon>::create();
<span class="comment">// Use the firstHorizon here...</span>
singularity<Horizon>::destroy();
<span class="comment">// Create using a non-default constructor.</span>
Horizon & secondHorizon = singularity<Horizon>::create(7);
<span class="comment">// Use the secondHorizon here...</span>
singularity<Horizon>::destroy();
<span class="keyword">return</span> 0;
}
</pre>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title" style="clear: both">
<a name="singularity.baseclass"></a><a class="link" href="#singularity.baseclass" title="Usage as a Base Class">Usage as a Base Class</a>
</h3></div></div></div>
<p>
Usage as a base class is shown as follows:
</p>
<pre class="programlisting">
<span class="preprocessor">#include</span> <singularity.hpp>
<span class="keyword">using</span> ::boost::singularity;
<span class="comment">// This is the class which will be singularized.</span>
<span class="comment">// Notice the private constructors and friend statement.</span>
<span class="comment">// Also notice the curiously recurring template pattern.</span>
<span class="keyword">class</span> Horizon : <span class="keyword">public</span> singularity<Horizon>
{
<span class="keyword">private</span>:
Horizon() {}
Horizon(int arg0) {}
...
FRIEND_CLASS_SINGULARITY;
};
int main()
{
<span class="comment">// Create using the default constructor.</span>
Horizon & firstHorizon = Horizon::create();
<span class="comment">// Use the firstHorizon here...</span>
Horizon::destroy();
<span class="comment">// Create using a non-default constructor.</span>
Horizon & secondHorizon = Horizon::create(7);
<span class="comment">// Use the secondHorizon here...</span>
Horizon::destroy();
<span class="keyword">return</span> 0;
}
</pre></div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title" style="clear: both">
<a name="singularity.globalaccess"></a><a class="link" href="#singularity.globalaccess" title="Enabling Global Access">Enabling Global Access</a>
</h3></div></div></div>
<p>
To enable global access to the instance through the get_global() member function, use create_global() instead of create() when instantiating the object. An example is shown:
</p>
<pre class="programlisting">
<span class="preprocessor">#include</span> <singularity.hpp>
<span class="keyword">using</span> ::boost::singularity;
<span class="keyword">class</span> Horizon
{
<span class="keyword">private</span>:
Horizon() {}
Horizon(int arg0) {}
...
FRIEND_CLASS_SINGULARITY;
};
int main()
{
<span class="comment">// Create using the default constructor.</span>
Horizon & horizon = singularity<Horizon>::create_global();
{
<span class="comment">// Someplace far away in the code.</span>
Horizon & sameHorizon = singularity<Horizon>::get_global();
<span class="comment">// Use the sameHorizon here...</span>
}
singularity<Horizon>::destroy();
<span class="keyword">return</span> 0;
}
</pre>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title" style="clear: both">
<a name="singularity.threadsafety"></a><a class="link" href="#singularity.threadsafety" title="Enabling Thread Safety">Enabling Thread Safety</a>
</h3></div></div></div>
<p>
To enable thread safety, supply a second template argument to singularity as "multi_threaded". An example is shown below:
</p>
<pre class="programlisting">
<span class="preprocessor">#include</span> <singularity.hpp>
<span class="keyword">using</span> ::boost::singularity;
<span class="keyword">using</span> ::boost::multi_threaded;
<span class="keyword">class</span> Horizon
{
<span class="keyword">private</span>:
Horizon() {}
Horizon(int arg0) {}
...
FRIEND_CLASS_SINGULARITY;
};
int main()
{
<span class="comment">// Create using the default constructor.</span>
Horizon & horizon = singularity<Horizon, multi_threaded>::create_global();
{
<span class="comment">// Someplace far away in the code.</span>
Horizon & sameHorizon = singularity<Horizon, multi_threaded>::get_global();
<span class="comment">// Use the sameHorizon here...</span>
}
singularity<Horizon, multi_threaded>::destroy();
<span class="keyword">return</span> 0;
}
</pre>
<p>
To use a thread safe singularity as a base class, inherit from singularity as shown below:
</p>
<pre class="programlisting">
<span class="keyword">class</span> Horizon : <span class="keyword">public</span> singularity<Horizon, multi_threaded>
</pre>
<p>
Because the Double-Checked Locking Pattern is not both thread-safe and portable (see Reference 3), the multi_threaded policy mutex is always acquired when calling on any member function of singularity. When using the singularity with create_global(), due to the performance impact of acquiring a mutex, it is recommended that get_global() be called infrequently, and the returned reference stored for later use.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="singularity.limitations"></a><a class="link" href="#singularity.limitations" title="Limitations">Limitations</a>
</h2></div></div></div>
<p>
As a generic wrapper class, singularity needs to perfectly forward the arguments passed from the create() function, into the singularized class. Unfortunately with C++03, this is not possible for an arbitrary number of arguments, without an O(2^n) implementation. This is known as the <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm">forwarding problem</a>.
</p>
<p>
Just like to Boost.Bind, most create() functions must receive their arguments as non-const references. However, for functions requiring up to 3 arguments, all arguments will be perfectly forwarded. The number of required create() functions is O(2^n), 2*(2^(n+1)-1) to be exact, so the default upper limit of 3 arguments requires generating 30 functions. Constructors which take additional arguments receive them as non-const references up to 10 arguments by default.
</p>
<pre class="programlisting">
<span class="preprocessor">#ifndef</span> BOOST_SINGULARITY_PERFECT_FORWARD_ARG_SIZE
<span class="preprocessor">#define</span> BOOST_SINGULARITY_PERFECT_FORWARD_ARG_SIZE 3
<span class="preprocessor">#endif</span>
<span class="preprocessor">#ifndef</span> BOOST_SINGULARITY_NONCONST_REFERENCE_ARG_SIZE
<span class="preprocessor">#define</span> BOOST_SINGULARITY_NONCONST_REFERENCE_ARG_SIZE 10
<span class="preprocessor">#endif</span>
</pre>
<p>
These arbitrary values can be redefined by the user before including the header, as appropriate for their needs. The specified number of forwarding create(...) functions will be automatically generated as required.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="singularity.customization"></a><a class="link" href="#singularity.customization" title="Customization">Customization</a>
</h2></div></div></div>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="singularity.threadingpolicy"></a><a class="link" href="#singularity.threadingpolicy" title="Threading Policy">Threading Policy</a>
</h2></div></div></div>
<p>
The supplied thread safe policy of multi_threaded is defined as follows:
</p>
<pre class="programlisting">
<span class="keyword">template</span> <<span class="keyword">class</span> T> <span class="keyword">class</span> multi_threaded
{
<span class="keyword">public</span>:
<span class="keyword">inline</span> multi_threaded()
{
lockable.lock();
}
<span class="keyword">inline</span> ~multi_threaded()
{
lockable.unlock();
}
<span class="keyword">private</span>:
<span class="keyword">static</span> ::boost::mutex lockable;
};
</pre>
<p>
Instantiation of this object creates an RAII style lock protecting access to the code in scope. Developers on small microcontrollers which do not support exceptions, will be unable to use this policy object, as the boost::mutex requires exceptions to be enabled. If for this, or any other reason, the developer is unable to use the supplied multi_threaded policy, an alternate policy can be implemented and supplied to singularity. The new policy need only acquire a mutex on construction, and release it upon destruction.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="singularity.references"></a><a class="link" href="#singularity.references" title="References">References</a>
</h2></div></div></div>
<ol>
<li><a class="link" href="http://blogs.msdn.com/b/scottdensmore/archive/2004/05/25/140827.aspx">Why Singletons are Evil</a>,
Scott Densmore, 2004
<li><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm" target="_blank">The Forwarding Problem</a>,
Peter Dimov, Howard E. Hinnant, Dave Abrahams, 2002</li>
<li><a href="http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf" target="_blank">C++ and the Perils of Double-Checked Locking</a>,
Scott Meyers and Andrei Alexandrescu, 2004</li>
<li><a href="http://software.intel.com/en-us/blogs/2007/11/30/volatile-almost-useless-for-multi-threaded-programming/" target="_blank">Volatile: Almost Useless for Multi-Threaded Programming</a>,
Arch Robison, 2007</li>
<li><a href="http://en.wikipedia.org/wiki/Design_Patterns" target="_blank">Design Patterns</a>,
Gamma et al. - Addison Wesley Publishing, 1995</li>
<li><a href="http://en.wikipedia.org/wiki/Modern_C%2B%2B_Design" target="_blank">Modern C++ Design</a>,
Andrei Alexandrescu, 2001</li>
<li><a href="http://www.boost.org/doc/libs/1_46_1/libs/bind/bind.html" target="_blank">Boost.Bind</a>,
Peter Dimov, 2001-2005</li>
</ol>
</div>
</body>