lock.h 7.7 KB
 Michal 'vorner' Vaner committed Aug 31, 2012 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 ``````// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. #ifndef B10_THREAD_LOCK_H #define B10_THREAD_LOCK_H #include #include // for NULL. namespace isc { namespace util { namespace thread { `````` JINMEI Tatuya committed Oct 10, 2012 25 ``````class CondVar; `````` Michal 'vorner' Vaner committed Aug 31, 2012 26 27 28 29 30 31 32 33 34 35 36 `````` /// \brief Mutex with very simple interface /// /// Since mutexes are very system dependant, we create our own wrapper around /// whatever is available on the system and hide it. /// /// To use this mutex, create it and then lock and unlock it by creating the /// Mutex::Locker object. /// /// Also, as mutex is a low-level system object, an error might happen at any /// operation with it. We convert many errors to the isc::InvalidOperation, `````` Michal 'vorner' Vaner committed Oct 02, 2012 37 38 39 40 41 ``````/// since the errors usually happen only when used in a wrong way. Any methods /// or constructors in this class can throw. Allocation errors are converted /// to std::bad_alloc (for example when OS-dependant limit of mutexes is /// exceeded). Some errors which usually mean a programmer error abort the /// program, since there could be no safe way to recover from them. `````` Michal 'vorner' Vaner committed Aug 31, 2012 42 43 44 ``````/// /// The current interface is somewhat minimalistic. If we ever need more, we /// can add it later. `````` JINMEI Tatuya committed Oct 10, 2012 45 ``````class Mutex : boost::noncopyable { `````` Michal 'vorner' Vaner committed Aug 31, 2012 46 47 48 ``````public: /// \brief Constructor. /// `````` Michal 'vorner' Vaner committed Oct 01, 2012 49 50 `````` /// Creates a mutex. It is a non-recursive mutex (can be locked just once, /// if the same threads tries to lock it again, Bad Things Happen). `````` Michal 'vorner' Vaner committed Aug 31, 2012 51 52 53 54 55 56 57 58 59 `````` /// /// Depending on compilation parameters and OS, the mutex may or may not /// do some error and sanity checking. However, such checking is meant /// only to aid development, not rely on it as a feature. /// /// \throw std::bad_alloc In case allocation of something (memory, the /// OS mutex) fails. /// \throw isc::InvalidOperation Other unspecified errors around the mutex. /// This should be rare. `````` Michal 'vorner' Vaner committed Oct 01, 2012 60 `````` Mutex(); `````` JINMEI Tatuya committed Sep 07, 2012 61 `````` `````` Michal 'vorner' Vaner committed Aug 31, 2012 62 63 `````` /// \brief Destructor. /// `````` JINMEI Tatuya committed Sep 28, 2012 64 `````` /// Destroys the mutex. It is not allowed to destroy a mutex which is `````` Michal 'vorner' Vaner committed Aug 31, 2012 65 66 `````` /// currently locked. This means a Locker created with this Mutex must /// never live longer than the Mutex itself. `````` JINMEI Tatuya committed Sep 07, 2012 67 68 `````` ~Mutex(); `````` Michal 'vorner' Vaner committed Aug 31, 2012 69 70 `````` /// \brief This holds a lock on a Mutex. /// `````` Michal 'vorner' Vaner committed Sep 26, 2012 71 `````` /// To lock a mutex, create a locker. It'll get unlocked when the locker `````` Michal 'vorner' Vaner committed Aug 31, 2012 72 73 74 75 76 77 `````` /// is destroyed. /// /// If you create the locker on the stack or using some other "garbage /// collecting" mechanism (auto_ptr, for example), it ensures exception /// safety with regards to the mutex - it'll get released on the exit /// of function no matter by what means. `````` JINMEI Tatuya committed Oct 10, 2012 78 `````` class Locker : boost::noncopyable { `````` Michal 'vorner' Vaner committed Aug 31, 2012 79 80 81 82 83 84 85 `````` public: /// \brief Constructor. /// /// Locks the mutex. May block for extended period of time. /// /// \throw isc::InvalidOperation when OS reports error. This usually /// means an attempt to use the mutex in a wrong way (locking `````` Michal 'vorner' Vaner committed Oct 01, 2012 86 `````` /// a mutex second time from the same thread, for example). `````` Michal 'vorner' Vaner committed Aug 31, 2012 87 `````` Locker(Mutex& mutex) : `````` JINMEI Tatuya committed Oct 15, 2012 88 `````` mutex_(mutex) `````` Michal 'vorner' Vaner committed Aug 31, 2012 89 90 91 `````` { mutex.lock(); } `````` JINMEI Tatuya committed Sep 07, 2012 92 `````` `````` Michal 'vorner' Vaner committed Aug 31, 2012 93 94 95 `````` /// \brief Destructor. /// /// Unlocks the mutex. `````` JINMEI Tatuya committed Sep 07, 2012 96 `````` ~Locker() { `````` JINMEI Tatuya committed Oct 15, 2012 97 `````` mutex_.unlock(); `````` Michal 'vorner' Vaner committed Aug 31, 2012 98 99 `````` } private: `````` JINMEI Tatuya committed Oct 15, 2012 100 `````` Mutex& mutex_; `````` Michal 'vorner' Vaner committed Aug 31, 2012 101 `````` }; `````` Michal 'vorner' Vaner committed Sep 05, 2012 102 103 104 105 106 107 108 109 `````` /// \brief If the mutex is currently locked /// /// This is debug aiding method only. And it might be unavailable in /// non-debug build (because keeping the state might be needlesly /// slow). /// /// \todo Disable in non-debug build bool locked() const; `````` Michal 'vorner' Vaner committed Aug 31, 2012 110 ``````private: `````` JINMEI Tatuya committed Oct 10, 2012 111 112 113 114 115 116 117 118 119 120 `````` friend class CondVar; // Commonly called after acquiring the lock, checking and updating // internal state for debug. void postLockAction(); // Commonly called before releasing the lock, checking and updating // internal state for debug. void preUnlockAction(); `````` Michal 'vorner' Vaner committed Sep 05, 2012 121 `````` class Impl; `````` Michal 'vorner' Vaner committed Aug 31, 2012 122 123 124 125 126 `````` Impl* impl_; void lock(); void unlock(); }; `````` JINMEI Tatuya committed Oct 10, 2012 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 ``````/// \brief Encapsulation for a condition variable. /// /// This class provides a simple encapsulation of condition variable for /// inter-thread synchronization. It has similar but simplified interface as /// that for \c pthread_bond_ variants. /// /// It uses the \c Mutex class object for the mutex used with the condition /// variable. Since for normal applications the internal \c Mutex::Locker /// class is the only available interface to acquire a lock, sample code /// for waiting on a condition variable would look like this: /// \code /// CondVar cond; /// Mutex mutex; /// { /// Mutex::Locker locker(mutex); /// while (some_condition) { /// cond.wait(mutex); /// } /// // do something under the protection of locker /// } // lock is released here /// \endcode /// Note that \c mutex passed to the \c wait() method must be the same one /// used to construct the \c locker. /// /// \note This class is defined as a friend class of \c Mutex and directly /// refers to and modifies private internals of the \c Mutex class. It breaks /// the assumption that the lock is only acquired or released via the /// \c Locker class and breaks other integrity assumption on \c Mutex, /// thereby making it more fragile, but we couldn't find other way to /// implement a safe and still simple realization of condition variables. /// So, this is a kind of compromise. If this class is needed to be /// extended, first consider a way to use public interfaces of \c Mutex; /// do not easily rely on the fact that this class is a friend of it. `````` JINMEI Tatuya committed Oct 10, 2012 160 161 ``````class CondVar : boost::noncopyable { public: `````` JINMEI Tatuya committed Oct 10, 2012 162 163 164 165 `````` /// \brief Constructor. /// /// \throw std::bad_alloc memory allocation failure /// \throw isc::Unexpected other unexpected shortage of system resource `````` JINMEI Tatuya committed Oct 10, 2012 166 `````` CondVar(); `````` JINMEI Tatuya committed Oct 10, 2012 167 168 169 170 171 172 `````` /// \brief Destructor. /// /// An object of this class must not be destructed while some thread /// is waiting on it. If this condition isn't met the destructor will /// terminate the program. `````` JINMEI Tatuya committed Oct 10, 2012 173 `````` ~CondVar(); `````` JINMEI Tatuya committed Oct 10, 2012 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 `````` /// \brief Wait on the condition variable. /// /// This method works like \c pthread_cond_wait(). For mutex it takes /// an \c Mutex class object. Unlike \c pthread_cond_wait(), however, /// this method requires a lock for the mutex has been acquired. /// If this condition isn't met, it can throw an exception (in the /// debug mode build) or result in undefined behavior. /// /// The lock will be automatically released within this method, and /// will be re-acquired on the exit of this method. /// /// \throw isc::InvalidOperation mutex isn't locked /// \throw isc::BadValue mutex is not a valid \c Mutex object /// /// \param mutex A \c Mutex object to be released on wait(). `````` JINMEI Tatuya committed Oct 10, 2012 190 `````` void wait(Mutex& mutex); `````` JINMEI Tatuya committed Oct 10, 2012 191 192 193 194 195 196 197 198 `````` /// \brief Unblock a thread waiting for the condition variable. /// /// This method waits one of other threads (if any) waiting on this object /// via the \c wait() call. /// /// This method never throws; if some unexpected low level error happens /// it terminates the program. `````` JINMEI Tatuya committed Oct 10, 2012 199 200 201 202 203 `````` void signal(); private: class Impl; Impl* impl_; }; `````` Michal 'vorner' Vaner committed Aug 31, 2012 204 `````` `````` JINMEI Tatuya committed Oct 10, 2012 205 206 207 ``````} // namespace thread } // namespace util } // namespace isc `````` Michal 'vorner' Vaner committed Aug 31, 2012 208 209 `````` #endif `````` JINMEI Tatuya committed Oct 10, 2012 210 211 212 213 `````` // Local Variables: // mode: c++ // End:``````