C++线程锁的封装,主要提供lock,unlock,require等操作,需要注意的是线程重复获取锁的问题,设置了一个count的计数器,该计算器之所以不考虑++,--的原子操作的问题,是因为该计数器本身就在lock与unlock中,所以本身是线程安全的。
另外mutable count是将count的变化操作防止在const方法中,保证方法语义。
class TC_ThreadCond;
/**
* 线程互斥对象
*/
struct TC_ThreadMutex_Exception : public TC_Lock_Exception
{
TC_ThreadMutex_Exception(const string &buffer) : TC_Lock_Exception(buffer){};
TC_ThreadMutex_Exception(const string &buffer, int err) : TC_Lock_Exception(buffer, err){};
~TC_ThreadMutex_Exception() throw() {};
};
/**
* 线程锁
*/
class TC_ThreadMutex
{
public:
TC_ThreadMutex();
virtual ~TC_ThreadMutex();
/**
* 加锁
*/
void lock() const;
/**
* 尝试锁
*
* @return bool
*/
bool tryLock() const;
/**
* 解锁
*/
void unlock() const;
/**
* 加锁后调用unlock是否会解锁, 给TC_Monitor使用的
* 永远返回true
*
* @return bool
*/
bool willUnlock() const { return true;}
protected:
// noncopyable
TC_ThreadMutex(const TC_ThreadMutex&);
void operator=(const TC_ThreadMutex&);
/**
* 计数
*/
int count() const;
/**
* 计数
*/
void count(int c) const;
friend class TC_ThreadCond;
protected:
mutable pthread_mutex_t _mutex;
};
/**
* 线程锁类
* 采用线程库实现
**/
class TC_ThreadRecMutex
{
public:
/**
* 构造函数
*/
TC_ThreadRecMutex();
/**
* 析够函数
*/
virtual ~TC_ThreadRecMutex();
/**
* 锁, 调用pthread_mutex_lock
* return : 返回pthread_mutex_lock的返回值
*/
int lock() const;
/**
* 解锁, pthread_mutex_unlock
* return : 返回pthread_mutex_lock的返回值
*/
int unlock() const;
/**
* 尝试锁, 失败抛出异常
* return : true, 成功锁; false 其他线程已经锁了
*/
bool tryLock() const;
/**
* 加锁后调用unlock是否会解锁, 给TC_Monitor使用的
*
* @return bool
*/
bool willUnlock() const;
protected:
/**
* 友元类
*/
friend class TC_ThreadCond;
/**
* 计数
*/
int count() const;
/**
* 计数
*/
void count(int c) const;
private:
/**
锁对象
*/
mutable pthread_mutex_t _mutex;
mutable int _count;
};
TC_ThreadMutex::TC_ThreadMutex()
{
int rc;
pthread_mutexattr_t attr;
rc = pthread_mutexattr_init(&attr);
assert(rc == 0);
rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
assert(rc == 0);
rc = pthread_mutex_init(&_mutex, &attr);
assert(rc == 0);
rc = pthread_mutexattr_destroy(&attr);
assert(rc == 0);
if(rc != 0)
{xxx
throw TC_ThreadMutex_Exception("[TC_ThreadMutex::TC_ThreadMutex] pthread_mutexattr_init error", rc);
}
}
TC_ThreadMutex::~TC_ThreadMutex()
{
int rc = 0;
rc = pthread_mutex_destroy(&_mutex);
assert(rc == 0);
}
void TC_ThreadMutex::lock() const
{
int rc = pthread_mutex_lock(&_mutex);
if(rc != 0)
{
if(rc == EDEADLK)
{
throw TC_ThreadMutex_Exception("[TC_ThreadMutex::lock] pthread_mutex_lock dead lock error", rc);
}
else
{
throw TC_ThreadMutex_Exception("[TC_ThreadMutex::lock] pthread_mutex_lock error", rc);
}
}
}
bool TC_ThreadMutex::tryLock() const
{
int rc = pthread_mutex_trylock(&_mutex);
if(rc != 0 && rc != EBUSY)
{
if(rc == EDEADLK)
{
throw TC_ThreadMutex_Exception("[TC_ThreadMutex::tryLock] pthread_mutex_trylock dead lock error", rc);
}
else
{
throw TC_ThreadMutex_Exception("[TC_ThreadMutex::tryLock] pthread_mutex_trylock error", rc);
}
}
return (rc == 0);
}
void TC_ThreadMutex::unlock() const
{
int rc = pthread_mutex_unlock(&_mutex);
if(rc != 0)
{
throw TC_ThreadMutex_Exception("[TC_ThreadMutex::unlock] pthread_mutex_unlock error", rc);
}
}
int TC_ThreadMutex::count() const
{
return 0;
}
void TC_ThreadMutex::count(int c) const
{
}
///
TC_ThreadRecMutex::TC_ThreadRecMutex()
: _count(0)
{
int rc;
pthread_mutexattr_t attr;
rc = pthread_mutexattr_init(&attr);
if(rc != 0)
{
throw TC_ThreadMutex_Exception("[TC_ThreadRecMutex::TC_ThreadRecMutex] pthread_mutexattr_init error", rc);
}
rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
if(rc != 0)
{
throw TC_ThreadMutex_Exception("[TC_ThreadRecMutex::TC_ThreadRecMutex] pthread_mutexattr_settype error", rc);
}
rc = pthread_mutex_init(&_mutex, &attr);
if(rc != 0)
{
throw TC_ThreadMutex_Exception("[TC_ThreadRecMutex::TC_ThreadRecMutex] pthread_mutex_init error", rc);
}
rc = pthread_mutexattr_destroy(&attr);
if(rc != 0)
{
throw TC_ThreadMutex_Exception("[TC_ThreadRecMutex::TC_ThreadRecMutex] pthread_mutexattr_destroy error", rc);
}
}
TC_ThreadRecMutex::~TC_ThreadRecMutex()
{
while (_count)
{
unlock();
}
int rc = 0;
rc = pthread_mutex_destroy(&_mutex);
assert(rc == 0);
}
int TC_ThreadRecMutex::lock() const
{
int rc = pthread_mutex_lock(&_mutex);
if(rc != 0)
{
throw TC_ThreadMutex_Exception("[TC_ThreadRecMutex::lock] pthread_mutex_lock error", rc);
}
if(++_count > 1)
{
rc = pthread_mutex_unlock(&_mutex);
assert(rc == 0);
}
return rc;
}
int TC_ThreadRecMutex::unlock() const
{
if(--_count == 0)
{
int rc = 0;
rc = pthread_mutex_unlock(&_mutex);
return rc;
}
return 0;
}
bool TC_ThreadRecMutex::tryLock() const
{
int rc = pthread_mutex_trylock(&_mutex);
if(rc != 0 )
{
if(rc != EBUSY)
{
throw TC_ThreadMutex_Exception("[TC_ThreadRecMutex::tryLock] pthread_mutex_trylock error", rc);
}
}
else if(++_count > 1)
{
rc = pthread_mutex_unlock(&_mutex);
if(rc != 0)
{
throw TC_ThreadMutex_Exception("[TC_ThreadRecMutex::tryLock] pthread_mutex_unlock error", rc);
}
}
return (rc == 0);
}
bool TC_ThreadRecMutex::willUnlock() const
{
return _count == 1;
}
int TC_ThreadRecMutex::count() const
{
int c = _count;
_count = 0;
return c;
}
void TC_ThreadRecMutex::count(int c) const
{
_count = c;
}