muduo源码Base
Mutex类 Condition类
首先看这个类
class noncopyable
{
public:
noncopyable(const noncopyable&) = delete;
void operator=(const noncopyable&) = delete;
protected:
noncopyable() = default;
~noncopyable() = default;
};
} // namespace muduo
noncopyable类 将拷贝构造函数以及运算符定为删除的 Mutex Condition类继承它 防止对这个两个类都要对各自的拷贝构造函数写成删除的 同时protected防止定义父类
接下来看Mutex这是一个RAII类
class CAPABILITY("mutex") MutexLock : noncopyable
{
public:
MutexLock()
: holder_(0)
{
MCHECK(pthread_mutex_init(&mutex_, NULL));
}
~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();
}
void assertLocked() const ASSERT_CAPABILITY(this)
{
assert(isLockedByThisThread());
}
// internal usage
void lock() ACQUIRE()
{
MCHECK(pthread_mutex_lock(&mutex_));
assignHolder();
}
void unlock() RELEASE()
{
unassignHolder();
MCHECK(pthread_mutex_unlock(&mutex_));
}
pthread_mutex_t* getPthreadMutex() /* non-const */
{
return &mutex_;
}
private:
friend class Condition;
class UnassignGuard : noncopyable
{
public:
explicit 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 SCOPED_CAPABILITY MutexLockGuard : noncopyable
{
public:
explicit MutexLockGuard(MutexLock& mutex) ACQUIRE(mutex)
: mutex_(mutex)
{
mutex_.lock();
}
~MutexLockGuard() RELEASE()
{
mutex_.unlock();
}
private:
MutexLock& mutex_;
};
MutexLock封装了对互斥锁的初始化 以及lock unlock操作 为什么要多一个MutexLockGuard将MutexLock作为自己的成员变量 这是RAII的技巧 在创建一个MutexLockGuard 对象时 初始化即加锁 利用C++特有的析构函数做解锁动作 每次使用将MutexLockGuard 作为栈上对象 即使抛出异常 也可以解锁 不会像C语言一样每次要判断是否成功 失败需要手动解锁
在MutexLock中还存在一个UnassuignGuard 也许会有人疑惑这个是干什么的?你难道没看到哪个holder_成员变量码??hhh这先等到看到·Condition类的使用才能明白
class Condition : noncopyable
{
public:
explicit Condition(MutexLock& mutex)
: mutex_(mutex)
{
MCHECK(pthread_cond_init(&pcond_, NULL));
}
~Condition()
{
MCHECK(pthread_cond_destroy(&pcond_));
}
void wait()
{
MutexLock::UnassignGuard ug(mutex_);
MCHECK(pthread_cond_wait(&pcond_, mutex_.getPthreadMutex()));
}
// returns true if time out, false otherwise.
bool waitForSeconds(double seconds);
void notify()
{
MCHECK(pthread_cond_signal(&pcond_));
}
void notifyAll()
{
MCHECK(pthread_cond_broadcast(&pcond_));
}
private:
MutexLock& mutex_;
pthread_cond_t pcond_;
};
其它的函数不用说了 主要看一下Wait 使用的是MutexLockGuard的私有成员变量 为什么不用MutexLockGuard呢?
因为要维护holder_和当前使用这个锁的线程的一致性 pthread_cond_wait会先释放互斥锁 阻塞在条件变量 等待满足再锁上互斥锁 如果使用MutexLockGuard的话 离开Wait后该线程依然拥有互斥锁 然而holder_变为了0 而UnassignGuard中析构函数 是将holder_恢复到线程的id