muduo的mutex_lock_guard()就是利用C++的RAII机制,完成互斥锁锁的自动加锁,解锁操作,解放双手。我们只需要用一堆大括号的控制互斥锁的范围就可以了。
RAII(Resource Acquisition Is Initialization),也称为“资源获取就是初始化”,是C++语言的一种管理资源、避免泄漏的惯用法。C++标准保证任何情况下,已构造的对象最终会销毁,即它的析构函数最终会被调用。简单的说,RAII 的做法是使用一个对象,在其构造时获取资源,在对象生命期控制对资源的访问使之始终保持有效,最后在对象析构的时候释放资源。
它有两个主要成员,MutexLock类和MutexlockGuard类。这两个类之间的关系仅仅只是关联关系,MutexLockGuard中使用了MutexLock中的
lock()和unlock()方法。它们之间不存在整体与局部的关系,如果存在整体与局部的关系,那就是聚合关系。如果不仅仅存在整体与局部的关系,并且还负责这个对象的生存期,那么就是组合关系。
它们的接口如图:
代码加注释如下:
class MutexLock : boost::noncopyable
{
public:
MutexLock()
: holder_(0)
{
MCHECK(pthread_mutex_init(&mutex_, NULL)); //MEMCHECK是多retval的检测,相当于assert,下同
}
~MutexLock()
{
assert(holder_ == 0); //只有在没有被其它线程持有的情况下才可以析构
MCHECK(pthread_mutex_destroy(&mutex_));
}
// must be called when locked, i.e. for assertion
bool isLockedByThisThread() const //是否被本线程上锁
{
return holder_ == CurrentThread::tid(); //返回id,通过systemcall + cache方式
}
void assertLocked() const
{
assert(isLockedByThisThread());
}
// internal usage
void lock()
{
MCHECK(pthread_mutex_lock(&mutex_));
assignHolder(); //赋值,赋上tid
}
//lock()和unlock()函数中两个语句顺序都不能乱
void unlock()
{
unassignHolder(); //首先要清零
MCHECK(pthread_mutex_unlock(&mutex_));
}
pthread_mutex_t* getPthreadMutex() /* non-const */
{
return &mutex_;
}
private:
friend class Condition;
class UnassignGuard : boost::noncopyable //取消赋值
{
public:
UnassignGuard(MutexLock& owner)
: owner_(owner)
{
owner_.unassignHolder();
}
~UnassignGuard()
{
owner_.assignHolder();
}
private:
MutexLock& owner_;
};
void unassignHolder()
{
holder_ = 0;
}
void assignHolder()
{
holder_ = CurrentThread::tid();
}
pthread_mutex_t mutex_;
pid_t holder_;
};
// Use as a stack variable, eg.
// int Foo::size() const
// {
// MutexLockGuard lock(mutex_);
// return data_.size();
// }
class MutexLockGuard : boost::noncopyable //我们用这个类,就是在利用C++的RAII机制,让锁在作用域内全自动化
{
public:
explicit MutexLockGuard(MutexLock& mutex)
: mutex_(mutex)
{
mutex_.lock();
}
~MutexLockGuard()
{
mutex_.unlock();
}
private:
MutexLock& mutex_; //为甚么要使用引用?因为他们仅仅是关联关系,使用引用不会导致MutexLock对象的销毁!!!
};
}
// Prevent misuse like:
// MutexLockGuard(mutex_);
// A tempory object doesn't hold the lock for long!
#define MutexLockGuard(x) error "Missing guard object name" //定义一个宏,防止定义一个无名临时MutexLockGuard对象,因为它不能够长时间拥有锁