Muduo网络库简介
muduo 是一个基于 Reactor 模式的现代 C++ 网络库,作者陈硕。它采用非阻塞 IO 模型,基于事件驱动和回调,原生支持多核多线程,适合编写 Linux 服务端多线程网络应用程序。
muduo网络库的核心代码只有数千行,在网络编程技术学习的进阶阶段,muduo是一个非常值得学习的开源库。目前我也是刚刚开始学习这个网络库的源码,希望将这个学习过程记录下来。这个网络库的源码已经发布在GitHub上,可以点击这里阅读。目前Github上这份源码已经被作者用c++11重写,我学习的版本是没有使用c++11版本的。不过二者大同小异,核心思想是没有变化的。点这里可以看我的源代码,如果你对我之前的博客有兴趣,可以点击下面的连接:
muduo网络库源码复现笔记(一):base库的Timestamp.h
muduo网络库源码复现笔记(二):base库的Atomic.h
muduo网络库源码复现笔记(三):base库的Exception.h
muduo网络库源码复现笔记(四):base库的Thread.h和CurrentThread.h
Mutex.h
熟悉操作系统编程的同学肯定对互斥量mutex不陌生,Mutex.h就是对互斥量mutex的操作做了一些封装,这个头文件里有两个类,分别是MutexLock和MutexGuard类,下面详细看一看。
MutexLock类
MutexLock类的封装很清晰,包括初始化、上锁、解锁、销毁的操作。
class MutexLock : boost::noncopyable
{
public:
MutexLock():holder_(0)//初始化mutex
{
int ret = pthread_mutex_init(&mutex_,NULL);
assert(ret == 0);(void) ret;
}
~MutexLock()//销毁mutex
{
assert(holder_ == 0);
int ret = pthread_mutex_destroy(&mutex_);
assert(ret == 0);(void)ret;
}
bool isLockedByThisThread()
{
return holder_ == CurrentThread::tid();
}
bool assertLocked()
{
assert(isLockedByThisThread());
}
void lock()//上锁
{
pthread_mutex_lock(&mutex_);
holder_ = CurrentThread::tid();
}
void unlock()//解锁
{
holder_ = 0;
pthread_mutex_unlock(&mutex_);
}
pthread_mutex_t* getPthreadMutex()
{
return &mutex_;
}
private:
pthread_mutex_t mutex_;
pid_t holder_;
};
MutexGuard类
MutexGurad类是对MutexLock类的又一层封装,主要实现的是Mutex的管理。
这个类很简单,唯一需要注意的是这个类的私有变量MutexLock是一个引用,所以当MutexGuard的对象生命周期结束时,mutex的生命周期并没有结束,即MutexGurad不能左右他所管理的Mutex的生命周期
class MutexLockGuard : boost::noncopyable
{
public:
explicit MutexLockGuard(MutexLock &mutex)
: mutex_(mutex)
{
mutex_.lock();
}
~MutexLockGuard()
{
mutex_.unlock();
}
private:
MutexLock &mutex_;
};
Condition.h
Condition.h是对Linux下的条件量的封装,包括初始化、等待操作、唤醒线程操作、销毁操作。条件量通常和互斥量一起协同控制线程。这个类同样也很简单,私有变量mutex同样也是引用类型。
class Condition : boost::noncopyable
{
public:
explicit Condition(MutexLock& mutex):mutex_(mutex)//初始化
{
pthread_cond_init(&pcond_,NULL);
}
~Condition()//销毁
{
pthread_cond_destroy(&pcond_);
}
void wait()//阻塞等待
{
pthread_cond_wait(&pcond_,mutex_.getPthreadMutex());
}
bool waitForSeconds(int seconds);
void notify()//唤醒一个随机线程
{
pthread_cond_signal(&pcond_);
}
void notifyAll()//唤醒所有线程
{
pthread_cond_broadcast(&pcond_);
}
private:
MutexLock& mutex_;
pthread_cond_t pcond_;
};
CountDownLatch.h
CountDownLatch.h包含的是CountDownLatch类。这个类是对互斥量与条件量的又一次封装。它的私有变量有三个,分别是互斥量mutex_、条件量condition_、计数器count。mutex_有一个修饰词mutable,故mutex_可以在被const修饰的函数内发生修改,count协同条件量工作,具体看下面函数类的讲解
class CountDownLatch : boost::noncopyable
{
public:
explicit CountDownLatch(int count);
void wait();
void countDown();
int getCount() const;//返回count_
private:
mutable MutexLock mutex_;
Condition condition_;
int count_;
};
构造函数CountDownLatch(int count)
这个函数很简单,列表初始化了三个私有成员,需要注意一下就是mutex_和condition_是外部类类型,必需用列表初始化的方式初始化
CountDownLatch::CountDownLatch(int count)
:mutex_(),condition_(mutex_),count_(count)
{
}
线程等待函数 wait()
我们以往我们在使用互斥量的时候,往往把它视作一个值,lock操作就是减一,unlock就是加一。实际上互斥量是一个结构体,这里count帮助互斥量用于计数,我们不必再把互斥量视作一个值。在wait函数中,当count大于0时,线程进入阻塞等待状态。
void CountDownLatch::wait()
{
MutexLockGuard lock(mutex_);
while(count_ > 0)
{
condition_.wait();
}
}
Count减操作 countDown()
countDown()和wait()可以协同工作,在countDown中,lock拿到锁之后,对count进行减操作,如果count为零,就唤醒所有线程。
void CountDownLatch::countDown()
{
MutexLockGuard lock(mutex_);
--count_;
if(count_ == 0)
{
condition_.notifyAll();
}
}