前言
muduo库也对线程同步原语封装了一下,为下面三个类:
(1) MutexLock (2)Condition (3) CountDownLatch
我将简化类,或以伪代码的形式作为讲解
mutex类
简化后的代码
class MutexLock : noncopyable
{
public:
MutexLock()
{
//pthread_mutex_init 系统调用 初始化一个锁
MCHECK(pthread_mutex_init(&mutex_, NULL));
}
~MutexLock()
{
//pthread_mutex_destroy 系统调用 销毁锁
MCHECK(pthread_mutex_destroy(&mutex_));
}
void lock()
{
//pthread_mutex_lock系统调用 加锁
MCHECK(pthread_mutex_lock(&mutex_));
}
void unlock()
{
//pthread_mutex_lock系统调用 解锁
MCHECK(pthread_mutex_unlock(&mutex_));
}
pthread_mutex_t* getPthreadMutex() /* non-const */
{
return &mutex_;
}
private:
friend class Condition;
pthread_mutex_t mutex_;
};
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()
{
//条件变量阻塞,所有使用该mutex_锁的线程会进入一个等待队列中,暂时无法获取锁
MCHECK(pthread_cond_wait(&pcond_, mutex_.getPthreadMutex()));
}
void notify()
{
//条件变量解除堵塞,通知堵塞队列中一个线程获取锁
MCHECK(pthread_cond_signal(&pcond_));
}
void notifyAll()
{
//条件变量解除堵塞,通知堵塞队列中所有线程去获取锁(注意锁争用)
MCHECK(pthread_cond_broadcast(&pcond_));
}
private:
MutexLock& mutex_;
pthread_cond_t pcond_;
};
CountDownLatch类
头文件代码
class CountDownLatch : noncopyable
{
public:
explicit CountDownLatch(int count);//避免传入bool等意义不明的参数,禁止隐式转换
void wait();//堵塞直到计数减到0
void countDown();
int getCount() const;
private:
mutable MutexLock mutex_;
Condition condition_ GUARDED_BY(mutex_);
int count_ GUARDED_BY(mutex_);//确保对count_ 的操作是原子的
};
构造函数为什么要exexplicit修饰
mutable作用是什么
源代码
CountDownLatch::CountDownLatch(int count)
: mutex_(),
condition_(mutex_),
count_(count)
{
}
void CountDownLatch::wait()
{
MutexLockGuard lock(mutex_);
//必须用循环,堵塞该函数调用之后的逻辑,count_ == 0时,解除堵塞
while (count_ > 0)
{
condition_.wait();
}
}
void CountDownLatch::countDown()
{
MutexLockGuard lock(mutex_);
--count_;
if (count_ == 0)
{
condition_.notifyAll();
}
}
int CountDownLatch::getCount() const
{
MutexLockGuard lock(mutex_);
return count_;
}
分析
void func(){
//创建CountDownLatch对象,设count_为线程数n
//创建n个线程,将CountDownLatch的指针作为线程传入参数传进去,
线程函数体中调用CountDownLatch->CountDownLatch方法,是count_--
//CountDownLatch.wait()
//其他逻辑
}
当n个线程运行起来后,CountDownLatch.wait()才会解除堵塞,进而执行后面的逻辑。
注意点1:
注意点2:
void CountDownLatch::countDown()
{
MutexLockGuard lock(mutex_);
--count_;
if (count_ == 0)
{
condition_.notifyAll();
}
}