Locks and Holds: The Basics of Synchronization
By Sergey Babkin, June 11, 2009
Two of the very basic primitives connecting a portion of code to a portion of data are locks and holds
Listing One
class Lock; // this is the basic lock
class AutoLock {
public:
AutoLock(Lock &arg) : lock_(arg)
{
lock_.lock();
}
~AutoLock()
{
lock_.unlock();
}
protected:
Lock &lock_;
};
// ... used like this ...
{
AutoLock al(myLock);
call();
}
Listing Two
class AutoUnlock {
public:
AutoUnlock(Lock &arg) : lock_(arg)
{
lock_.unlock();
}
~AutoUnlock()
{
lock_.lock();
}
protected:
Lock &lock_;
};
// ... used like this ...
{
AutoLock al(myLock);
for(...) {
SomeClass variable;
...
{
AutoUnlock au(myLock);
long_operation();
}
...
}
}
Listing Three
class Hold {
public:
Hold() : count_(0), waiting_(0)
{
pthread_mutex_init(&mutex_, NULL);
pthread_cond_init(&cond_, NULL);
}
~Hold()
{
pthread_mutex_destroy(&mutex_);
pthread_cond_destroy(&cond_);
}
void getHold()
{
pthread_mutex_lock(&mutex_);
++count_;
pthread_mutex_unlock(&mutex_);
}
void releaseHold()
{
pthread_mutex_lock(&mutex_);
if (--count_ == 0 && waiting_ != 0)
pthread_cond_broadcast(&cond_);
pthread_mutex_unlock(&mutex_);
}
void wait()
{
pthread_mutex_lock(&mutex_);
while(count_ != 0) {
++waiting_;
pthread_cond_wait(&cond_, &mutex_);
--waiting_;
}
pthread_mutex_unlock(&mutex_);
}
protected:
pthread_mutex_t mutex_; // access to count_
pthread_cond_t cond_; // signalled when count_ drops to 0
int count_; // count of holds
int waiting_; // count of threads waiting for release
private: // prevent the copy constructors and assignments
Hold(const Hold&);
void operator=(const Hold&);
};