IMHO, you don't need the method to return the status; consider throwing an exception should a runtime error occur. After all, the point of the wrapper class is to avoid exposing OS-dependent interfaces to the user, right?
As for exposing the pthread_mutex_t, I also would not recommend doing that. The pthread_mutex_t should be an attribute of your Mutex class, not a reference to an external object (which could be destroyed, manipulated, etc). As for your ConditionMutex class, it should contain a Mutex object.
Here's some code I threw together in the past when trying to mimic the Boost Thread Library (I jokingly called it 'liteboost'):
mutex.hpp:
Code:
/*
# Copyright (C) 2008 David M. Whitney (aka "dwhitney67")
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
#this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LITE_BOOST_MUTEX_H
#define LITE_BOOST_MUTEX_H
#include <pthread.h>
#include <stdexcept>
namespace liteboost
{
class condition;
class mutex
{
public:
mutex(int kind = PTHREAD_MUTEX_DEFAULT)
{
pthread_mutexattr_t attr;
if (pthread_mutexattr_init(&attr) != 0)
{
throw std::runtime_error("Mutex::initMutex() -- failed to init attr.");
}
if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE) != 0)
{
throw std::runtime_error("Mutex::initMutex() -- failed to set attr process type.");
}
if (pthread_mutexattr_settype(&attr, kind) != 0)
{
throw std::runtime_error("Mutex::initMutex() -- failed to set attr type.");
}
if (pthread_mutex_init(&m_mutex, &attr) != 0)
{
throw std::runtime_error("Mutex::initMutex() -- failed to init mutex attr.");
}
}
~mutex()
{
if (pthread_mutex_destroy(&m_mutex) != 0)
{
throw std::runtime_error("Mutex::~Mutex() -- unable to destroy the mutex.");
}
}
class scoped_lock
{
public:
scoped_lock(mutex& mutex) : m_mutex(mutex)
{
m_mutex.lock();
}
~scoped_lock()
{
m_mutex.unlock();
}
private:
mutex& m_mutex;
};
private:
friend class condition;
void lock()
{
if (pthread_mutex_lock(&m_mutex) != 0)
{
throw std::runtime_error("Mutex::lock() -- unable to lock the mutex.");
}
}
void unlock()
{
if (pthread_mutex_unlock(&m_mutex) != 0)
{
throw std::runtime_error("Mutex::unlock() -- unable to unlock the mutex.");
}
}
pthread_mutex_t* get_mutex()
{
return &m_mutex;
}
pthread_mutex_t m_mutex;
};
} // end namespace
#endif
condition.hpp:
Code:
/*
# Copyright (C) 2008 David M. Whitney (aka "dwhitney67")
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
#this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LITE_BOOST_CONDITION_H
#define LITE_BOOST_CONDITION_H
#include <liteboost/thread/mutex.hpp>
#include <pthread.h>
#include <sys/time.h>
#include <cerrno>
#include <limits>
#include <stdexcept>
namespace liteboost
{
class condition
{
public:
condition()
{
pthread_condattr_t attr;
if (pthread_condattr_init(&attr) != 0)
{
throw std::runtime_error("condition(): pthread_condattr_init() failed.");
}
if (pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE) != 0)
{
throw std::runtime_error("condition(): pthread_condattr_setpshared() failed.");
}
if (pthread_cond_init(&m_cond, &attr) != 0)
{
throw std::runtime_error("condition(): pthread_condattr_init() failed.");
}
}
~condition()
{
if (pthread_cond_destroy(&m_cond) != 0)
{
throw std::runtime_error("~condition(): pthread_cond_destroy() failed.");
}
}
void wait()
{
if (pthread_cond_wait(&m_cond, m_mutex.get_mutex()) != 0)
{
throw std::runtime_error("wait(): pthread_cond_wait() failed.");
}
}
bool timed_wait(const unsigned int waitTime_ns)
{
static const unsigned int NANOSECS_PER_SEC = 1000000000;
static const unsigned int NANOSECS_PER_USEC = 1000;
// Convert given nanosecond time into an abstime (absolute time)
struct timeval td;
gettimeofday(&td, 0);
struct timespec t;
t.tv_sec = td.tv_sec + (waitTime_ns / NANOSECS_PER_SEC);
t.tv_nsec = (td.tv_usec * NANOSECS_PER_USEC) + (waitTime_ns % NANOSECS_PER_SEC);
// Check for overflow in the computed nanoseconds
if ((unsigned int)t.tv_nsec >= NANOSECS_PER_SEC)
{
t.tv_sec += 1;
t.tv_nsec -= NANOSECS_PER_SEC;
}
// Loop until the condition signal is received, or a timeout occurs
while (1)
{
switch (pthread_cond_timedwait(&m_cond, m_mutex.get_mutex(), &t))
{
// Everything is ok; condition-lock was obtained.
case 0:
return true;
// Timeout occurred before receiving a signal; condition-lock was not obtained.
case ETIMEDOUT:
return false;
// Error occurred.
default:
throw std::runtime_error("timed_wait(): pthread_cond_timedwait() failed.");
}
}
}
void signal()
{
if (pthread_cond_signal(&m_cond) != 0)
{
throw std::runtime_error("signal(): phread_cond_signal() failed.");
}
}
void broadcast()
{
if (pthread_cond_broadcast(&m_cond) != 0)
{
throw std::runtime_error("signal(): phread_cond_broadcast() failed.");
}
}
class scoped_cond_lock
{
public:
scoped_cond_lock(condition& cond) : m_cond(cond)
{
m_cond.lock();
}
~scoped_cond_lock()
{
m_cond.unlock();
}
private:
condition& m_cond;
};
private:
void lock()
{
m_mutex.lock();
}
void unlock()
{
m_mutex.unlock();
}
pthread_cond_t m_cond;
mutex m_mutex;
};
} // end namespace
#endif
Sample usage:
Code:
#include "liteboost/thread/mutex.hpp"
#include <map>
#include <stdexcept>
class SharedObject
{
private:
typedef std::map<unsigned int, unsigned int> MyMap;
typedef MyMap::const_iterator MyMapIter;
public:
static SharedObject& instance();
void insert(const unsigned int key, const unsigned int value);
unsigned int getValue(const unsigned int key);
private:
SharedObject() {}
MyMap m_map;
liteboost::mutex m_mutex;
};
SharedObject&
SharedObject::instance()
{
static SharedObject obj;
return obj;
}
void
SharedObject::insert(const unsigned int key, const unsigned int value)
{
liteboost::mutex::scoped_lock lock(m_mutex);
m_map[key] = value;
}
unsigned int
SharedObject::getValue(const unsigned int key)
{
liteboost::mutex::scoped_lock lock(m_mutex);
MyMapIter it = m_map.find(key);
if (it == m_map.end())
{
throw std::runtime_error("SharedObject::getValue() -- key not found!");
}
return it->second;
}