Files
pvAccess/pvAccessApp/utils/namedLockPattern.h
2011-05-12 12:47:55 +02:00

150 lines
3.8 KiB
C++

/*
* namedLockPattern.h
*/
#ifndef NAMEDLOCKPATTERN_H
#define NAMEDLOCKPATTERN_H
#include <map>
#include <iostream>
#include <lock.h>
#include <pvType.h>
#include "referenceCountingLock.h"
// TODO implement using smart pointers
namespace epics { namespace pvAccess {
/**
* NamedLockPattern
*/
template <class Key, class Compare = std::less<Key> >
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 <code>true</code> if acquired, <code>false</code> 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<const Key,ReferenceCountingLock*,Compare> _namedLocks;
typename std::map<const Key,ReferenceCountingLock*,Compare>::iterator _namedLocksIter;
/**
* Release synchronization lock for named object.
* @param name name of the object whose lock to release.
* @param release set to <code>false</code> if there is no need to call release
* on synchronization lock.
*/
void releaseSynchronizationObject(const Key& name,const bool release);
};
template <class Key, class Compare>
bool NamedLockPattern<Key,Compare>::acquireSynchronizationObject(const Key& name, const epics::pvData::int64 msec)
{
ReferenceCountingLock* 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 = 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 <class Key, class Compare>
void NamedLockPattern<Key,Compare>::releaseSynchronizationObject(const Key& name)
{
releaseSynchronizationObject(name, true);
}
template <class Key, class Compare>
void NamedLockPattern<Key,Compare>::releaseSynchronizationObject(const Key& name,const bool release)
{
epics::pvData::Lock guard(_mutex);
ReferenceCountingLock* 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);
delete lock;
}
}
}
template <class Key, class Compare>
class NamedLock : private epics::pvData::NoDefaultMethods
{
public:
NamedLock(NamedLockPattern<Key,Compare>* 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<Key,Compare>* _namedLockPattern;
};
}}
#endif /* NAMEDLOCKPATTERN_H */