锁的裸用
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, &mutex_attr);
pthread_cond_t cond;
pthread_cond_init(&cond, &cond_attr)
//
pthread_mutex_lock(&mutex);
while (condition is false)
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
我认为这种方式有两个劣势:
其一,锁的代码与业务代码杂糅在一起,显得臃肿,可读性不高。
其二,没有使用面向对象与封装概念,每次使用,都需要手动初始化。
锁的封装
thread_mutex
对互斥锁进行封装,thread_cond
对条件变量进行封装,而ThreadLocker
将互斥锁与条件变量进行统一管理,对外提供接口:
void Lock() // 加锁
void UnLock() // 解锁
bool TryLock() // 尝试枷锁,true 为加锁成功
void Notify() // 唤醒,同signal
void NotifyAll() // 全部唤醒,同broadcast
void Wait() // 等待
bool TimedWait(int millisecond) // 等待一定时间
锁的管理
C++中有一种技术为RAII,即资源获取即初始化。这样,程序员不需要关心锁的释放工作,锁在离开作用域后,自动释放。
void Func()
{
Lock lock(_locker);
// do something
}
有了上述模型以后,对锁进行管理,设计如下:
template <typename T>
class LockerManager
{
public:
explicit LockerManager(T *locker) : _locker(locker)
{
_locker->Lock();
}
~LockerManager()
{
_locker->UnLock();
}
protected:
LockerManager(const LockerManager &);
LockerManager &operator=(const LockerManager &);
private:
T *_locker;
};
对象在离开作用域时,自动析构,调用析构函数。因而,在析构函数中,调用解锁操作。