Re: Locking arbitrary resources without creating objects on the heap (longish)
You can do this without a heap based object.
First, you need a base type, call it BaseLock:
struct BaseLock { };
next you need a templated subclass. Note that I have not
compiled/tested this code, this is from memory:
teplate <typename T>
struct LockClass : public BaseLock {
explicit LockClass(T& lock) : m_lock(lock), m_enabled(true) {
m_lock.lock();
}
~LockClass() {
if (m_enabled) m_lock.unlock();
}
LockClass(const LockClass &rhs) : m_lock(rhs.m_lock),
m_enabled(rhs.m_enabled) {
rhs.m_enabled=false;
}
//hold a reference to the lock
T& m_lock;
//only one owner of the 'lock' at a time
mutable bool m_enabled;
};
And a constructor function:
template <typename T>
inline LockClass<T> make_lock(T& lock) {
return LockClass<t>(lock);
}
Now, to use it:
//locks lock, will unlock when falls out of scope.
const BaseLock & lock = make_lock(mymutex);
this relies on the fact that the const reference to the base class will
bind to the temporary and the temporary will not be destroyed until the
reference falls out of scope.
that isn't that clean looking, so there are a few ways to make it even
nicer.
First:
typedef const BaseLock & GenericLock;
now you can do:
GenericLock lock = make_lock(mymutex);
Better, but it would be nice if you could automatically create a region
as well.
I've even gotten this to work:
LockRegion(mymutex) {
//locked code here
}
To get that to work, you need to add a test to the base class so it can
be tested:
struct BaseLock {
operator bool() const { return false; }
};
and a macro:
#define LockRegion(x) if (const BaseLock & lock = make_lock(x) { } else
Here is how the macro works. First, it creats an if and declares a
scoped const reference to the base. This reference is bound to the
temporary returned by make_lock. make_lock locks the mutex. When the
last reference to the temporary is destroyed (the one bound to the
const reference) the lock is unlocked. That happens when one of the
two statements following the if is completed. The BaseLock is then
queried by calling operator bool. operator bool returns false, so we
enter the 'else' block, which is your code immediately following the
LockRegion:
LockRegion(mylock) {
//foo
}
expands to:
if (const BaseLock & lock = make_lock( mylock ) { } else {
//foo
}
I keep meaning to write an article about this technique but I haven't
had the time.
I hope this helps
joshua lehrer
http://www.lehrerfamily.com/
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]