/** * Copyright - See the COPYRIGHT that is included with this distribution. * pvAccessCPP is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. */ #ifndef NAMEDLOCKPATTERN_H #define NAMEDLOCKPATTERN_H #include #include #include #include #include #include // TODO implement using smart pointers namespace epics { namespace pvAccess { /** * NamedLockPattern */ template > class NamedLockPattern { public: /** * Constructor. */ NamedLockPattern() {}; /** * Destructor. */ virtual ~NamedLockPattern() {}; /** * Acquire synchronization lock for named object. * * NOTE: Argument msecs is currently not supported due to * Darwin OS not supporting pthread_mutex_timedlock. May be changed in the future. * * @param name name of the object whose lock to acquire. * @param msec the number of milleseconds to wait. * An argument less than or equal to zero means not to wait at all. * @return true if acquired, false othwerwise. * NOTE: currently this routine always returns true. Look above for explanation. */ bool acquireSynchronizationObject(const Key& name, const epics::pvData::int64 msec); /** * Release synchronization lock for named object. * @param name name of the object whose lock to release. */ void releaseSynchronizationObject(const Key& name); private: epics::pvData::Mutex _mutex; std::map _namedLocks; typename std::map::iterator _namedLocksIter; /** * Release synchronization lock for named object. * @param name name of the object whose lock to release. * @param release set to false if there is no need to call release * on synchronization lock. */ void releaseSynchronizationObject(const Key& name,const bool release); }; template bool NamedLockPattern::acquireSynchronizationObject(const Key& name, const epics::pvData::int64 msec) { ReferenceCountingLock::shared_pointer lock; { //due to guard epics::pvData::Lock guard(_mutex); _namedLocksIter = _namedLocks.find(name); // get synchronization object // none is found, create and return new one // increment references if(_namedLocksIter == _namedLocks.end()) { lock.reset(new ReferenceCountingLock()); _namedLocks[name] = lock; } else { lock = _namedLocksIter->second; lock->increment(); } } // end of guarded area bool success = lock->acquire(msec); if(!success) { releaseSynchronizationObject(name, false); } return success; } template void NamedLockPattern::releaseSynchronizationObject(const Key& name) { releaseSynchronizationObject(name, true); } template void NamedLockPattern::releaseSynchronizationObject(const Key& name,const bool release) { epics::pvData::Lock guard(_mutex); ReferenceCountingLock::shared_pointer lock; _namedLocksIter = _namedLocks.find(name); // release lock if (_namedLocksIter != _namedLocks.end()) { lock = _namedLocksIter->second; // release the lock if (release) { lock->release(); } // if there only one current lock exists // remove it from the map if (lock->decrement() <= 0) { _namedLocks.erase(_namedLocksIter); } } } template class NamedLock : private epics::pvData::NoDefaultMethods { public: NamedLock(NamedLockPattern* namedLockPattern): _namedLockPattern(namedLockPattern) {} bool acquireSynchronizationObject(const Key& name, const epics::pvData::int64 msec) {_name = name; return _namedLockPattern->acquireSynchronizationObject(name,msec);} ~NamedLock(){_namedLockPattern->releaseSynchronizationObject(_name);} private: Key _name; NamedLockPattern* _namedLockPattern; }; }} #endif /* NAMEDLOCKPATTERN_H */