|
Boost : |
From: brent verner (brent_at_[hidden])
Date: 2000-08-14 10:36:51
On 14 Aug 2000 at 08:39 (-0500), jsiek_at_[hidden] wrote:
| William Kempf writes:
| > I think it makes as much sense to nest the CV as it does the lock.
| > The CV can't exist with out the mutex, while the mutex can exist
| > withou the CV. Further, the CV is going to be as dependent
| > [ clip ]
| > > > while (!full)
| > > > lock.wait(cv);
| > >
| > > while (!full)
| > > cv.wait(lock);
| > >
| > > makes a little more sense to me.
| >
| > It makes more sense because it follows the logic of the pthreads
| > implementation. However, I think it makes sense to reverse them in
| > our own library because the lock is waiting on the condition.
|
| The fact that the Mutex concept can exist without the CV concept is an
| argument for my position, not yours ;) The Mutex concept should not
| make any mention of a CV. Having a CV typedef nested in Mutex, or
| having a wait() function in the Mutex's lock would make the Mutex
| concept dependent on the CV concept, which is the opposite of what we
| want. We want tight coupling, but it should go in the other direction.
A condition variable must always be associated with a
mutex, to avoid the race condition where a thread prepares
to wait on a condition variable and another thread signals
the condition just before the first thread actually waits
on it.
Having the condition class derive from the mutex class will _enforce_
the required behavior from the (pthreads) condition variable.
something like below. note: i know, it's bad code, but I hope
you get the idea...
Brent
=======================================================
class basic_lockable {
public:
basic_lockable(){}
virtual ~basic_lockable(){}
virtual int lock() = 0;
virtual int unlock() = 0;
};
template<typename __lock_t>
class basic_scoped_lock {
private:
__lock_t* _M_lock;
public:
basic_scoped_lock(__lock_t* arg) : _M_lock(arg){
_M_lock->lock();
}
~basic_scoped_lock(){
_M_lock->unlock();
}
};
typedef basic_scoped_lock<basic_lockable> scoped_lock;
class basic_mutex : public virtual basic_lockable {
private:
pthread_mutex_t me_id;
public:
basic_mutex() : basic_sharable() {
pthread_mutex_init(&me_id, NULL);
}
virtual ~basic_mutex(){
pthread_mutex_destroy(&me_id);
}
inline int lock(){
return pthread_mutex_lock(&me_id);
}
inline int trylock(){ return pthread_mutex_trylock(&me_id); }
inline int unlock(){
return pthread_mutex_unlock(&me_id);
}
};
class basic_condition : public basic_mutex
{
private:
pthread_cond_t cond_id;
public:
basic_condition() {
pthread_cond_init(&cond_id, NULL);
}
virtual ~basic_condition(){
pthread_cond_destroy(&cond_id);
}
inline int wait(){
return pthread_cond_wait(&cond_id,&me_id);
}
inline int wait(long usec){
timespec then;
timeval now;
gettimeofday(&now,NULL);
int sec = usec / 1000000;
usec = usec - sec * 1000000;
then.tv_sec = now.tv_sec + sec;
then.tv_nsec = (now.tv_usec + usec) * 1000;
return pthread_cond_timedwait(&cond_id,&me_id,&then);
}
inline int broadcast(){
return pthread_cond_broadcast(&cond_id);
}
inline int signal(){
return pthread_cond_signal(&cond_id);
}
};
class basic_semaphore : public virtual basic_lockable {
private:
sem_t sem_id;
int sem_count;
protected:
public:
basic_semaphore(int counti = 0) {
sem_init(&sem_id, 0, count);
}
virtual ~basic_semaphore(){
sem_destroy(&sem_id);
}
inline int trywait(){
return sem_trywait(&sem_id);
}
inline int post(){
return sem_post(&sem_id);
}
inline int wait(){
return sem_wait(&sem_id);
}
inline int value(){
sem_getvalue(&sem_id, &sem_count);
return sem_count;
}
inline int lock(){
// how do semaphores lock ?
}
inline int unlock(){
// and unlock ?
}
};
-- Damon Brent Verner o _ _ _ Cracker Jack® Surprise Certified _o /\_ _ \\o (_)\__/o (_) brent_at_[hidden] _< \_ _>(_) (_)/<_ \_| \ _|/' \/ brent_at_[hidden] (_)>(_) (_) (_) (_) (_)' _\o_
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk