first check-in of feisty meow codebase. many things broken still due to recent
[feisty_meow.git] / core / library / basis / mutex.h
1 #ifndef MUTEX_CLASS
2 #define MUTEX_CLASS
3
4 /*****************************************************************************\
5 *                                                                             *
6 *  Name   : mutex                                                             *
7 *  Author : Chris Koeritz                                                     *
8 *                                                                             *
9 *******************************************************************************
10 * Copyright (c) 1996-$now By Author.  This program is free software; you can  *
11 * redistribute it and/or modify it under the terms of the GNU General Public  *
12 * License as published by the Free Software Foundation; either version 2 of   *
13 * the License or (at your option) any later version.  This is online at:      *
14 *     http://www.fsf.org/copyleft/gpl.html                                    *
15 * Please send any updates to: fred@gruntose.com                               *
16 \*****************************************************************************/
17
18 #include "contracts.h"
19
20 //! A simple primitive class that encapsulates OS support for mutual exclusion.
21 /*!
22   The word "mutex" is an abbreviation for "mutual exclusion".  The mutex
23   provides a simple synchronization object that supports the programming of
24   critical sections.  It is guaranteed to be safe for threads, but it is only
25   useful within one application rather than between multiple applications.
26   The mutex_base is hardly ever used directly; instead the mutex class should
27   be used.
28 */
29
30 namespace basis {
31
32 class mutex : public virtual base_synchronizer
33 {
34 public:
35   mutex();  //!< Constructs a new mutex.
36
37   virtual ~mutex();
38     //!< Destroys the mutex.  It should not be locked upon destruction.
39
40   //! Constructor for use with malloc/free instead of new/delete.
41   void construct();
42
43   //! Destructor for use with malloc/free instead of new/delete.
44   void destruct();
45
46   void lock();
47     //!< Clamps down on the mutex, if possible.
48     /*!< Otherwise the current thread is blocked until the mutex is unlocked. */
49
50   void unlock();
51     //!< Gives up the possession of the mutex.
52
53   virtual void establish_lock();
54     //!< Satisfies base class requirements for locking.
55   virtual void repeal_lock();
56     //!< Satisfies base class requirements for unlocking.
57
58 private:
59   void *c_os_mutex;  //!< OS version of the mutex.
60
61   void defang();
62     //!< Removes the underlying OS synchronization primitive.
63     /*!< This method renders this mutex object inoperable.  This is useful
64     when the reason for the lock has vanished, but the mutex object cannot be
65     deleted yet.  Sometimes it may still be referred to, but there is no
66     longer any critical section to be protected. */
67
68   mutex(const mutex &);  //!< not allowed.
69   mutex &operator =(const mutex &);  //!< not allowed.
70 };
71
72 //////////////
73
74 //! auto_synchronizer simplifies concurrent code by automatically unlocking.
75 /*!
76   This relies on the base_synchronizer for the form of the objects that
77   will provide synchronization.  The synchronization object is locked when the
78   auto_synchronizer is created and it is unlocked when the auto_synchronizer
79   is destroyed.  This is most useful when the auto_synchronizer is an automatic
80   object; the synchronization lock is grabbed at the point of creation (even
81   in the middle of a function) and it is released when the function or block
82   scope exits, thus freeing us of the responsibility of always unlocking the
83   object before exiting from the critical section.
84
85   More Detail:
86   The auto_synchronizer provides an easy way to provide nearly idiot-proof
87   synchronization of functions that share the same locking object.  By giving
88   the synchronizer a working object that's derived from synchronization_base,
89   its mere construction establishes the lock and its destruction releases the
90   lock.  Thus you can protect a critical section in a function by creating
91   the auto_synchronizer at the top of the function as an automatic object, or
92   wherever in the function body is appropriate.  When the function exits, the
93   auto_synchronizer will be destroyed as part of the cleanup and the lock will
94   be released.  If there are multiple synchronization objects in a function,
95   then be very careful.  One must order them appropriately to avoid a deadlock.
96  
97   for example: @code
98     mutex my_lock;  // the real synchronization primitive.
99     ...  // lots of program in between.
100     int calculate_average() {
101       // our function that must control thread concurrency.
102       auto_synchronizer syncho(my_lock);  // establishes the lock.
103       ...  // lots of stuff done in the function in safety from other threads.
104     } // end of the function. @endcode
105  
106   Note that there was no unlock of the mutex above.  Remembering to unlock
107   synchronization primitives is one of the most troublesome requirements of
108   programming with multiple threads; the auto_synchronizer can be used in
109   many situations to automate the release of the lock.
110 */
111
112 class auto_synchronizer
113 {
114 public:
115   auto_synchronizer(base_synchronizer &locker) : _locker(locker)
116           { _locker.establish_lock(); }
117     //!< Construction locks the "locker" object for the current program scope.
118     /*!< This automatically locks a synchronization object until the current
119     scope (such as a function or even just a block) is exited, which implements
120     synchronization without needing multiple unlock calls before every return
121     statement. */
122
123   ~auto_synchronizer() { _locker.repeal_lock(); }
124     //!< Releases the lock as this object goes out of scope.
125
126 private:
127   base_synchronizer &_locker;  //!< the locking object.
128
129   // disallowed.
130   auto_synchronizer(const auto_synchronizer &locker);
131   auto_synchronizer &operator =(const auto_synchronizer &locker);
132 };
133
134 } //namespace.
135
136 #endif
137