root/trunk/dep/include/zthread/ThreadLocal.h @ 2

Revision 2, 11.1 kB (checked in by yumileroy, 17 years ago)

[svn] * Proper SVN structure

Original author: Neo2003
Date: 2008-10-02 16:23:55-05:00

Line 
1/*
2 * Copyright (c) 2005, Eric Crahen
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is furnished
9 * to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 *
21 */
22
23#ifndef __ZTTHREADLOCAL_H__
24#define __ZTTHREADLOCAL_H__
25
26#include "zthread/ThreadLocalImpl.h"
27
28namespace ZThread {
29
30  /**
31   * @class ThreadLocal
32   *
33   * @author Eric Crahen <http://www.code-foo.com>
34   * @date <2003-07-27T11:18:21-0400>
35   * @version 2.3.0
36   *
37   * Provides access to store and retrieve value types to and from a thread local
38   * storage context. A thread local storage context consists of the calling thread
39   * a specific ThreadLocal object. Since this context is specific to each thread
40   * whenever a value is stored in a ThreadLocal that is accessible from multiple
41   * threads, it can only be retrieved by the thread that stored it.
42   *
43   * The first time a thread accesses the value associated with a thread local storage
44   * context, a value is created. That value is either an initial value (determined by
45   * InitialValueT) or an inherited value (determined by ChildValueT).
46   *
47   * - If a threads parent had no value associated with a ThreadLocal when the thread was created,
48   *   then the InitialValueT functor is used to create an initial value.
49   *
50   * - If a threads parent did have a value associated with a ThreadLocal when the thread was
51   *   created, then the childValueT functor is used to create an initial value.
52   *
53   * Not all ThreadLocal's support the inheritance of values from parent threads. The default
54   * behavoir is to create values through the InitialValueT functor for all thread when
55   * they first access a thread local storage context.
56   *
57   * - Inheritance is enabled automatically when a user supplies a ChildValueT functor other
58   *   than the default one supplied.
59   *
60   * - Inheritance can be controlled explicitly by the user through a third functor,
61   *   InheritableValueT.
62   *
63   * <h2>Examples</h2>
64   *
65   * - <a href="#ex1">Default initial value</a>
66   * - <a href="#ex2">User-specified initial value</a>
67   * - <a href="#ex3">User-specified inherited value</a>
68   *
69   * <h2><a name="ex1">Default initial value</a></h2>
70   * A ThreadLocal that does not inherit, and uses the default value
71   * for an int as its initial value.
72   *
73   * @code
74   *
75   * #include "zthread/ThreadLocal.h"
76   * #include "zthread/Thread.h"
77   * #include <iostream>
78   *
79   * using namespace ZThread;
80   *
81   * class aRunnable : public Runnable {
82   *   ThreadLocal<int> localValue;
83   * public:
84   *   void run() {
85   *     std::cout << localValue.get() << std::endl;
86   *   }
87   * };
88   *
89   * int main() {
90   *
91   *   // Create a shared task to display ThreadLocal values
92   *   Task task(new aRunnable);
93   *
94   *   Thread t0(task); t0.wait();
95   *   Thread t1(task); t1.wait();
96   *   Thread t2(task); t2.wait();
97   *
98   *   // Output:
99   *
100   *   // 0
101   *   // 0
102   *   // 0
103   *
104   *   return 0;
105   *
106   * }
107   *
108   * @endcode
109   *
110   * <h2><a name="ex2">User-specified initial value</a></h2>
111   * A ThreadLocal that does not inherit, and uses a custom initial value.
112   *
113   * @code
114   *
115   * #include "zthread/ThreadLocal.h"
116   * #include "zthread/Thread.h"
117   * #include <iostream>
118   *
119   * using namespace ZThread;
120   *
121   * struct anInitialValueFn {
122   *   int operator()() {
123   *     static int next = 100;
124   *     int val = next; next += 100;
125   *     return val;
126   *   }
127   * };
128   *
129   * class aRunnable : public Runnable {
130   *   ThreadLocal<int, anInitialValueFn> localValue;
131   * public:
132   *   void run() {
133   *     std::cout << localValue.get() << std::endl;
134   *   }
135   * };
136   *
137   * int main() {
138   *
139   *   // Create a shared task to display ThreadLocal values
140   *   Task task(new aRunnable);
141   *
142   *   Thread t0(task); t0.wait();
143   *   Thread t1(task); t1.wait();
144   *   Thread t2(task); t2.wait();
145   *
146   *   // Output:
147   *
148   *   // 100
149   *   // 200
150   *   // 300
151   *
152   *   return 0;
153   *
154   * }
155   *
156   * @endcode
157   *
158   * <h2><a name="ex3">User-specified inherited value</a></h2>
159   * A ThreadLocal that does inherit and modify child values.
160   * (The default initial value functor is used)
161   *
162   * @code
163   *
164   * #include "zthread/ThreadLocal.h"
165   * #include "zthread/Thread.h"
166   * #include <iostream>
167   *
168   * using namespace ZThread;
169   *
170   * struct anInheritedValueFn {
171   *   int operator()(int val) {
172   *     return val + 100;
173   *   }
174   * };
175   *
176   * // This Runnable associates no ThreadLocal value in the main thread; so
177   * // none of the child threads have anything to inherit.
178   * class aRunnable : public Runnable {
179   *   ThreadLocal<int, ThreadLocalImpl::InitialValueFn<int>, anInheritedValueFn> localValue;
180   * public:
181   *   void run() {
182   *     std::cout << localValue.get() << std::endl;
183   *   }
184   * };
185   *
186   * // This Runnable associates a ThreadLocal value in the main thread which
187   * // is inherited when the child threads are created.
188   * class anotherRunnable : public Runnable {
189   *   ThreadLocal<int, ThreadLocalImpl::InitialValueFn<int>, anInheritedValueFn> localValue;
190   * public:
191   *   anotherRunnable() {
192   *     localValue.set(100);
193   *   }
194   *   void run() {
195   *     std::cout << localValue.get() << std::endl;
196   *   }
197   * };
198   *
199   * int main() {
200   *
201   *   // Create a shared task to display ThreadLocal values
202   *   Task task(new aRunnable);
203   *
204   *   Thread t0(task); t0.wait();
205   *   Thread t1(task); t1.wait();
206   *   Thread t2(task); t2.wait();
207   *
208   *   // Output:
209   *
210   *   // 0
211   *   // 0
212   *   // 0
213   *
214   *   task = Task(new anotherRunnable);
215   *
216   *   Thread t10(task); t10.wait();
217   *   Thread t11(task); t11.wait();
218   *   Thread t12(task); t12.wait();
219   *
220   *   // Output:
221   *
222   *   // 200
223   *   // 200
224   *   // 200
225   *
226   *   return 0;
227   *
228   * }
229   *
230   * @endcode
231   *
232   * <h2>Parameters</h2>
233   *
234   * <em>InitialValueT</em>
235   *
236   * This template parameter should indicate the functor used to set
237   * the initial value. It should support the following operator:
238   *
239   * <code>
240   * // required operator
241   * T operator()
242   *
243   * // supported expression
244   * InitialValueT()()
245   * </code>
246   *
247   *
248   * <em>ChildValueT</em>
249   *
250   * This template parameter should indicate the functor used to set
251   * the value that will be inherited by thread whose parent have associated
252   * a value with the ThreadLocal's context at the time they are created.
253   * It should support the following operator:
254   *
255   * <code>
256   * // required operator
257   * T operator(const T& parentValue)
258   *
259   * // supported expression
260   * ChildValueT()(parentValue)
261   * </code>
262   *
263   *
264   * <em>InheritableValueT</em>
265   *
266   * This template parameter should indicate the functor, used to determine
267   * wheather or not this ThreadLocal will allow values from a parent threads
268   * context to be inherited by child threads when they are created.
269   * It should support the following operator:
270   *
271   * <code>
272   * // required operator
273   * bool operator(const T& childValueFunctor)
274   *
275   * // supported expression
276   * InheritableValueT()( ChildValueT() )
277   * </code>
278   *
279   */
280  template <
281    typename T, 
282    typename InitialValueT      = ThreadLocalImpl::InitialValueFn<T>,
283    typename ChildValueT        = ThreadLocalImpl::UniqueChildValueFn, 
284    typename InheritableValueT  = ThreadLocalImpl::InheritableValueFn
285    >
286    class ThreadLocal : private ThreadLocalImpl {
287
288      typedef ThreadLocalImpl::ValuePtr ValuePtr;
289
290      class Value : public ThreadLocalImpl::Value {
291       
292        T value;
293       
294      public:
295       
296        Value() : value( InitialValueT()() ) { }
297       
298        Value(const Value& v) : value( ChildValueT()(v.value) ) { }
299       
300        virtual ~Value() { } 
301       
302        operator T() { return value; }
303       
304        const Value& operator=(const T& v) { value = v; }
305       
306        virtual bool isInheritable() const {
307          return InheritableValueT()( ChildValueT() );
308        }
309       
310        virtual ValuePtr clone() const {
311          return ValuePtr( new Value(*this) );
312        }
313       
314      };
315     
316      static ValuePtr createValue() {
317        return ValuePtr( new Value );
318      }
319     
320    public:
321
322    /**
323     * Get the value associated with the context (this ThreadLocal and
324     * the calling thread) of the invoker. If no value is currently
325     * associated, then an intial value is created and associated; that value
326     * is returned.
327     *
328     * @return <em>T</em> associated value.
329     *
330     * @post  If no value has been associated with the invoking context
331     *        then an inital value will be associated. That value is
332     *        created by the <em>InitialValueT</em> functor.   
333     */
334    T get() const { 
335      return (T)reinterpret_cast<Value&>( *value(&createValue) );
336    }
337 
338    /**
339     * Replace the value associated with the context (this ThreadLocal and
340     * the calling thread) of the invoker. If no value is currently
341     * associated, then an intial value is first created and subsequently
342     * replaced by the new value.
343     *
344     * @param v value of type <em>T</em> to associate.
345     *
346     * @post  If no value has been associated with the invoking context
347     *        then an inital value will first be associated. That value is
348     *        created by the <em>InitialValueT</em> functor and then
349     *        replaced with the new value.   
350     */
351    void set(T v) const {
352      reinterpret_cast<Value&>( *value(&createValue) ) = v;
353    }
354
355    /**
356     * Remove any value current associated with this ThreadLocal.
357     *
358     * @post Upon thier next invocation the get() and set() functions will behave as
359     *       if no value has been associated with this ThreadLocal and an
360     *       initial value will be generated.
361     */
362    void clear() const {
363      ThreadLocalImpl::clear();
364    }
365
366    /**
367     * Remove any value current associated with <em>any</em> ThreadLocal.
368     *
369     * @post Upon thier next invocation the get() and set() functions will behave as
370     *       if no value has been associated with <em>any</em> ThreadLocal and new
371     *       initial values will be generated.
372     */
373    static void clearAll() {
374      ThreadLocalImpl::clearAll();
375    }
376
377  };
378
379
380} // namespace ZThread
381
382#endif // __ZTTHREADLOCAL_H__
Note: See TracBrowser for help on using the browser.