4 /*****************************************************************************\
7 * Author : Chris Koeritz *
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 \*****************************************************************************/
18 #include "contracts.h"
20 //! A simple primitive class that encapsulates OS support for mutual exclusion.
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
32 class mutex : public virtual base_synchronizer
35 mutex(); //!< Constructs a new mutex.
38 //!< Destroys the mutex. It should not be locked upon destruction.
40 //! Constructor for use with malloc/free instead of new/delete.
43 //! Destructor for use with malloc/free instead of new/delete.
47 //!< Clamps down on the mutex, if possible.
48 /*!< Otherwise the current thread is blocked until the mutex is unlocked. */
51 //!< Gives up the possession of the mutex.
53 virtual void establish_lock();
54 //!< Satisfies base class requirements for locking.
55 virtual void repeal_lock();
56 //!< Satisfies base class requirements for unlocking.
59 void *c_os_mutex; //!< OS version of the mutex.
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. */
68 mutex(const mutex &); //!< not allowed.
69 mutex &operator =(const mutex &); //!< not allowed.
74 //! auto_synchronizer simplifies concurrent code by automatically unlocking.
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.
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.
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
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.
112 class auto_synchronizer
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
123 ~auto_synchronizer() { _locker.repeal_lock(); }
124 //!< Releases the lock as this object goes out of scope.
127 base_synchronizer &_locker; //!< the locking object.
130 auto_synchronizer(const auto_synchronizer &locker);
131 auto_synchronizer &operator =(const auto_synchronizer &locker);