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

Revision 2, 11.7 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 __ZTGUARD_H__
24#define __ZTGUARD_H__
25
26#include "zthread/NonCopyable.h"
27#include "zthread/Exceptions.h"
28
29namespace ZThread { 
30
31//
32// GuardLockingPolicyContract {
33//
34// createScope(lock_type&) 
35// bool createScope(lock_type&, unsigned long) 
36// destroyScope(lock_type&) 
37//
38// }
39//
40
41/**
42 * @class LockHolder
43 * @author Eric Crahen <http://www.code-foo.com>
44 * @date <2003-07-16T17:55:42-0400>
45 * @version 2.2.0
46 *
47 * This is a simple base class for Guards class. It allows Guards
48 * that have compatible targets to refer to each others targets
49 * allowing for the construction of Guards that share the same lock
50 * but have different locking policies.
51 */
52template <class LockType>
53class LockHolder {
54
55  LockType &_lock;
56  bool _enabled;
57
58 public:
59
60  template <class T>
61  LockHolder(T& t) : _lock(extract(t)._lock), _enabled(true) { }
62 
63  LockHolder(LockHolder& holder) : _lock(holder._lock), _enabled(true) { }
64
65  LockHolder(LockType& lock) : _lock(lock), _enabled(true) { }
66
67  void disable() { 
68    _enabled = false;
69  }
70
71  bool isDisabled() {
72    return !_enabled;
73  }
74
75  LockType& getLock() {
76    return _lock;
77  }
78
79 protected:
80
81  template <class T> 
82  static LockHolder& extract(T& t) {
83    // Design and Evolution of C++, page 328
84    return (LockHolder&)(t);
85  }
86
87};
88
89/**
90 * @class CompoundScope
91 * @author Eric Crahen <http://www.code-foo.com>
92 * @date <2003-07-16T17:55:42-0400>
93 * @version 2.2.0
94 *
95 * Locking policy that aggregates two policies that share a target.
96 * It is not appropriate to use with any type of OverlappedScope
97 */
98template <class Scope1, class Scope2>
99class CompoundScope {
100 public:
101
102  template <class LockType>
103  static void createScope(LockHolder<LockType>& l) {
104
105    Scope1::createScope(l);
106    Scope2::createScope(l);
107
108  }
109
110  template <class LockType>
111  static void createScope(LockHolder<LockType>& l, unsigned long ms) {
112
113    if(Scope1::createScope(l, ms))
114      if(!Scope2::createScope(l, ms)) {
115
116        Scope1::destroyScope(l);
117        return false;
118
119      }
120       
121    return true;
122
123  }
124
125  template <class LockType>
126  static void destroyScope(LockHolder<LockType>& l) {
127
128    Scope1::destroyScope(l);
129    Scope2::destroyScope(l);
130
131  }
132
133};
134
135
136/**
137 * @class LockedScope
138 * @author Eric Crahen <http://www.code-foo.com>
139 * @date <2003-07-16T17:55:42-0400>
140 * @version 2.2.0
141 *
142 * Locking policy for Lockable objects. This policy acquire()s a Lockable
143 * when the protection scope is created, and it release()s a Lockable
144 * when the scope is destroyed.
145 */
146class LockedScope {
147 public:
148
149  /**
150   * A new protection scope is being created by l2, using an existing scope
151   * created by l1.
152   *
153   * @param lock1 LockType1& is the LockHolder that holds the desired lock
154   * @param lock2 LockType1& is the LockHolder that wants to share
155  template <class LockType1, class LockType2>
156  static void shareScope(LockHolder<LockType1>& l1, LockHolder<LockType2>& l2) {
157   
158    l2.getLock().acquire();
159
160  }
161   */
162
163  /**
164   * A new protection scope is being created.
165   *
166   * @param lock LockType& is a type of LockHolder.
167   */
168  template <class LockType>
169  static bool createScope(LockHolder<LockType>& l, unsigned long ms) {
170
171    return l.getLock().tryAcquire(ms);
172
173  }
174
175  /**
176   * A new protection scope is being created.
177   *
178   * @param lock LockType& is a type of LockHolder.
179   */
180  template <class LockType>
181  static void createScope(LockHolder<LockType>& l) {
182
183    l.getLock().acquire();
184
185  }
186
187  /**
188   * A protection scope is being destroyed.
189   *
190   * @param lock LockType& is a type of LockHolder.
191   */
192  template <class LockType>
193  static void destroyScope(LockHolder<LockType>& l) {
194
195    l.getLock().release();
196
197  }
198
199};
200
201
202/**
203 * @class UnlockedScope
204 * @author Eric Crahen <http://www.code-foo.com>
205 * @date <2003-07-16T17:55:42-0400>
206 * @version 2.2.0
207 *
208 * Locking policy for Lockable objects. This policy release()s a Lockable
209 * when the protection scope is created, and it acquire()s a Lockable
210 * when the scope is destroyed.
211 */
212class UnlockedScope {
213 public:
214
215  /**
216   * A new protection scope is being created by l2, using an existing scope
217   * created by l1.
218   *
219   * @param lock1 LockType1& is the LockHolder that holds the desired lock
220   * @param lock2 LockType1& is the LockHolder that wants to share
221   */
222  template <class LockType1, class LockType2>
223  static void shareScope(LockHolder<LockType1>& /*l1*/, LockHolder<LockType2>& l2) {
224
225    l2.getLock().release();
226
227  }
228
229  /**
230   * A new protection scope is being created.
231   *
232   * @param lock LockType& is a type of LockHolder.
233  template <class LockType>
234  static void createScope(LockHolder<LockType>& l) {
235
236    l.getLock().release();
237
238  }
239   */
240
241  /**
242   * A protection scope is being destroyed.
243   *
244   * @param lock LockType& is a type of LockHolder.
245   */
246  template <class LockType>
247  static void destroyScope(LockHolder<LockType>& l) {
248
249    l.getLock().acquire();
250
251  }
252
253};
254 
255
256
257/**
258 * @class TimedLockedScope
259 * @author Eric Crahen <http://www.code-foo.com>
260 * @date <2003-07-16T17:55:42-0400>
261 * @version 2.2.0
262 *
263 * Locking policy that attempts to enterScope some resource
264 * in a certain amount of time using an tryEnterScope-relase protocol.
265 */
266template <int TimeOut>
267class TimedLockedScope {
268 public:
269
270  /**
271   * Try to enterScope the given LockHolder.
272   *
273   * @param lock LockType& is a type of LockHolder.
274   */
275  template <class LockType1, class LockType2>
276  static void shareScope(LockHolder<LockType1>& l1, LockHolder<LockType2>& l2) {
277
278    if(!l2.getLock().tryAcquire(TimeOut))
279      throw Timeout_Exception();
280       
281  }
282
283  template <class LockType>
284  static void createScope(LockHolder<LockType>& l) {
285
286    if(!l.getLock().tryAcquire(TimeOut))
287      throw Timeout_Exception();
288
289  }
290
291  template <class LockType>
292  static void destroyScope(LockHolder<LockType>& l) {
293
294    l.getLock().release();
295
296  }
297
298};
299
300
301/**
302 * @class OverlappedScope
303 * @author Eric Crahen <http://www.code-foo.com>
304 * @date <2003-07-16T17:55:42-0400>
305 * @version 2.2.0
306 *
307 * Locking policy allows the effective scope of two locks to overlap
308 * by releasing and disabling one lock before its Guard does so.
309 */
310class OverlappedScope {
311 public:
312
313  template <class LockType1, class LockType2>
314  static void transferScope(LockHolder<LockType1>& l1, LockHolder<LockType2>& l2) {
315
316    l1.getLock().acquire();
317
318    l2.getLock().release();
319    l2.disable();
320
321  }
322
323  template <class LockType>
324  static void destroyScope(LockHolder<LockType>& l) {
325
326    l.getLock().release();
327
328  }
329
330};
331
332
333
334/**
335 * @class Guard
336 * @author Eric Crahen <http://www.code-foo.com>
337 * @date <2003-07-16T17:55:42-0400>
338 * @version 2.2.0
339 *
340 * Scoped locking utility. This template class can be given a Lockable
341 * synchronization object and can 'Guard' or serialize access to
342 * that method.
343 * 
344 * For instance, consider a case in which a class or program have a 
345 * Mutex object associated with it. Access can be serialized with a
346 * Guard as shown below.
347 *
348 * @code
349 *
350 * Mutex _mtx;
351 * void guarded() {
352 *
353 *    Guard<Mutex> g(_mtx);
354 *
355 * }
356 *
357 * @endcode
358 *
359 * The Guard will lock the synchronization object when it is created and
360 * automatically unlock it when it goes out of scope. This eliminates
361 * common mistakes like forgetting to unlock your mutex.
362 *
363 * An alternative to the above example would be
364 *
365 * @code
366 *
367 * void guarded() {
368 *
369 *     (Guard<Mutex>)(_mtx);
370 *
371 * }
372 *
373 * @endcode
374 *
375 * HOWEVER; using a Guard in this method is dangerous. Depending on your
376 * compiler an anonymous variable like this can go out of scope immediately
377 * which can result in unexpected behavior. - This is the case with MSVC
378 * and was the reason for introducing assertions into the Win32_MutexImpl
379 * to track this problem down
380 *
381 */
382template <class LockType, class LockingPolicy = LockedScope>
383class Guard : private LockHolder<LockType>, private NonCopyable {
384
385  friend class LockHolder<LockType>;
386
387public:
388 
389  /**
390   * Create a Guard that enforces a the effective protection scope
391   * throughout the lifetime of the Guard object or until the protection
392   * scope is modified by another Guard.
393   *
394   * @param lock LockType the lock this Guard will use to enforce its
395   * protection scope.
396   * @post the protection scope may be ended prematurely
397   */
398  Guard(LockType& lock) : LockHolder<LockType>(lock) {
399
400    LockingPolicy::createScope(*this);
401
402  };
403
404  /**
405   * Create a Guard that enforces a the effective protection scope
406   * throughout the lifetime of the Guard object or until the protection
407   * scope is modified by another Guard.
408   *
409   * @param lock LockType the lock this Guard will use to enforce its
410   * protection scope.
411   * @post the protection scope may be ended prematurely
412   */
413  Guard(LockType& lock, unsigned long timeout) : LockHolder<LockType>(lock) {
414
415    if(!LockingPolicy::createScope(*this, timeout))
416      throw Timeout_Exception();
417
418  };
419
420  /**
421   * Create a Guard that shares the effective protection scope
422   * from the given Guard to this Guard.
423   *
424   * @param g Guard<U, V> guard that is currently enabled
425   * @param lock LockType the lock this Guard will use to enforce its
426   * protection scope.
427   */
428  template <class U, class V>
429  Guard(Guard<U, V>& g) : LockHolder<LockType>(g) {
430
431    LockingPolicy::shareScope(*this, extract(g));
432   
433  }
434
435  /**
436   * Create a Guard that shares the effective protection scope
437   * from the given Guard to this Guard.
438   *
439   * @param g Guard guard that is currently enabled
440   * @param lock LockType the lock this Guard will use to enforce its
441   * protection scope.
442   */
443  Guard(Guard& g) : LockHolder<LockType>(g) {
444
445    LockingPolicy::shareScope(*this, g);
446   
447  }
448
449
450  /**
451   * Create a Guard that transfers the effective protection scope
452   * from the given Guard to this Guard.
453   *
454   * @param g Guard<U, V> guard that is currently enabled
455   * @param lock LockType the lock this Guard will use to enforce its
456   * protection scope.
457   */
458  template <class U, class V>
459  Guard(Guard<U, V>& g, LockType& lock) : LockHolder<LockType>(lock) {
460
461    LockingPolicy::transferScope(*this, extract(g));
462
463  }
464
465
466  /**
467   * Create a Guard that transfers the effective protection scope
468   * from the given Guard to this Guard.
469   *
470   * @param g Guard guard that is currently enabled
471   * @param lock LockType the lock this Guard will use to enforce its
472   * protection scope.
473   */
474  Guard(Guard& g, LockType& lock) : LockHolder<LockType>(lock) {
475
476    LockingPolicy::transferScope(*this, g);
477
478  }
479 
480
481  /**
482   * Unlock a given Lockable object with the destruction of this Guard
483   */
484  ~Guard() throw();
485
486}; /* Guard */
487
488
489template <class LockType, class LockingPolicy>
490Guard<LockType, LockingPolicy>::~Guard() throw() {
491   
492  try {
493   
494    if(!this->isDisabled())
495      LockingPolicy::destroyScope(*this);
496   
497  } catch (...) { /* ignore */ } 
498 
499}
500
501
502};
503
504#endif // __ZTGUARD_H__
505
506
507
508
509
510
511
Note: See TracBrowser for help on using the browser.