// ********************************************************************** // // Copyright (c) 2003-2004 ZeroC, Inc. All rights reserved. // // This copy of Ice is licensed to you under the terms described in the // ICE_LICENSE file included in this distribution. // // ********************************************************************** #ifndef ICE_UTIL_RW_REC_MUTEX_H #define ICE_UTIL_RW_REC_MUTEX_H #include #include #include namespace IceUtil { template class RLockT { public: RLockT(const T& mutex) : _mutex(mutex) { _mutex.readLock(); _acquired = true; } ~RLockT() { if (_acquired) { _mutex.unlock(); } } void acquire() const { if (_acquired) { throw ThreadLockedException(__FILE__, __LINE__); } _mutex.readLock(); _acquired = true; } bool tryAcquire() const { if (_acquired) { throw ThreadLockedException(__FILE__, __LINE__); } _acquired = _mutex.tryReadLock(); return _acquired; } bool timedAcquire(const Time& timeout) const { if (_acquired) { throw ThreadLockedException(__FILE__, __LINE__); } _acquired = _mutex.timedReadLock(timeout); return _acquired; } void release() const { if (!_acquired) { throw ThreadLockedException(__FILE__, __LINE__); } _mutex.unlock(); _acquired = false; } bool acquired() const { return _acquired; } void upgrade() const { _mutex.upgrade(); } bool timedUpgrade(const Time& timeout) const { return _mutex.timedUpgrade(timeout); } protected: // TryRLockT's constructors RLockT(const T& mutex, bool) : _mutex(mutex) { _acquired = _mutex.tryReadLock(); } RLockT(const T& mutex, const Time& timeout) : _mutex(mutex) { _acquired = _mutex.timedReadLock(timeout); } private: // Not implemented; prevents accidental use. // RLockT(const RLockT&); RLockT& operator=(const RLockT&); const T& _mutex; mutable bool _acquired; }; template class TryRLockT : public RLockT { public: TryRLockT(const T& mutex) : RLockT(mutex, true) { } TryRLockT(const T& mutex, const Time& timeout) : RLockT(mutex, timeout) { } }; template class WLockT { public: WLockT(const T& mutex) : _mutex(mutex) { _mutex.writeLock(); _acquired = true; } ~WLockT() { if (_acquired) { _mutex.unlock(); } } void acquire() const { if (_acquired) { throw ThreadLockedException(__FILE__, __LINE__); } _mutex.writeLock(); _acquired = true; } bool tryAcquire() const { if (_acquired) { throw ThreadLockedException(__FILE__, __LINE__); } _acquired = _mutex.tryWriteLock(); return _acquired; } bool timedAcquire(const Time& timeout) const { if (_acquired) { throw ThreadLockedException(__FILE__, __LINE__); } _acquired = _mutex.timedWriteLock(timeout); return _acquired; } void release() const { if (!_acquired) { throw ThreadLockedException(__FILE__, __LINE__); } _mutex.unlock(); _acquired = false; } bool acquired() const { return _acquired; } protected: // TryWLockT's constructor WLockT(const T& mutex, bool) : _mutex(mutex) { _acquired = _mutex.tryWriteLock(); } WLockT(const T& mutex, const Time& timeout) : _mutex(mutex) { _acquired = _mutex.timedWriteLock(timeout); } private: // Not implemented; prevents accidental use. // WLockT(const WLockT&); WLockT& operator=(const WLockT&); const T& _mutex; mutable bool _acquired; }; template class TryWLockT : public WLockT { public: TryWLockT(const T& mutex) : WLockT(mutex, true) { } TryWLockT(const T& mutex, const Time& timeout) : WLockT(mutex, timeout) { } }; // // Concurrency primitive that allows many readers & one writer access // to a data structure. Writers have priority over readers. The // structure is not strictly fair in that there is no absolute queue // of waiting writers - that is managed by a condition variable. // // Both Reader & Writer mutexes can be recursively locked. Calling // upgrade() or timedUpgrade() while holding a read lock promotes // the reader to a writer lock. // class ICE_UTIL_API RWRecMutex { public: // // RLock (reader) & WLock (writer) typedefs. // typedef RLockT RLock; typedef TryRLockT TryRLock; typedef WLockT WLock; typedef TryWLockT TryWLock; RWRecMutex(); ~RWRecMutex(); // // Note that readLock/writeLock & unlock in general should not be // used directly. Instead use RLock & WLock. // // // Acquire a read lock. // void readLock() const; // // Try to acquire a read lock. // bool tryReadLock() const; // // Try to acquire a read lock for upto the given timeout. // bool timedReadLock(const Time&) const; // // Acquire a write lock. // void writeLock() const; // // Acquire a write lock. // bool tryWriteLock() const; // // Acquire a write lock for up to the given timeout. // bool timedWriteLock(const Time&) const; // // Unlock the reader/writer lock. // void unlock() const; // // Upgrade the read lock to a writer lock. Note that this method // can only be called if the reader lock is not held recursively. // void upgrade() const; // // Upgrade the read lock to a writer lock for up to the given // timeout Note that this method can only be called if the reader // lock is not held recursively. // bool timedUpgrade(const Time&) const; private: // noncopyable RWRecMutex(const RWRecMutex&); void operator=(const RWRecMutex&); // // Number of readers holding the lock. A positive number indicates // readers are active. A negative number means that a writer is // active. // mutable int _count; // // If there is an active writer this is the ID of the writer thread. // mutable ThreadId _writerId; // // Number of waiting writers. // mutable unsigned int _waitingWriters; // // Internal mutex. // Mutex _mutex; // // Two condition variables for waiting readers & writers. // mutable Cond _readers; mutable Cond _writers; }; } // End namespace IceUtil #endif