muduo网络库设计与实现(一)
文章目录
这是根据陈硕的《linux多线程服务端编程》中的“ muduo网络库设计与实现”部分写的简单笔记。具体代码可以参考陈硕的github。虽然大体框架一样,但也有些许不同,文章最后也会把我的代码放出来。
这是第一部分,主要实现
Reactor
模型的框架。
base
这部分是一些工具类的封装。最重要的是多线程相关的函数接口的封装,主要包括
- Thread:线程的创建和等待结束
- MutexLock:mutex的创建,销毁,加锁,解锁
- Condition:条件变量的创建,销毁,等待,通知,广播
除此之外还有更高层的封装,例如ThreadPool,CountDownLatch等。
noncopyable
有两种思路
- 一种使用
delete
关键字修饰拷贝构造函数和拷贝赋值函数 - 第二种将拷贝构造函数和拷贝赋值函数设置为private
class noncopyable {
public:
noncopyable(const noncopyable&) = delete;
const noncopyable& operator=( const noncopyable& ) = delete;
protected:
noncopyable() = default;
~noncopyable() = default;
};
Mutex
包括类MutexLock
和类MutexLockGuard
,这两个类都比较简单,所以就不过多介绍
class MutexLock : noncopyable{
public:
MutexLock() : holder_(0){
pthread_mutex_init(&mutex_, NULL);
}
~MutexLock(){
pthread_mutex_lock(&mutex_);
pthread_mutex_destroy(&mutex_);
}
bool isLockByThisThread(){
return holder_ == CurrentThread::tid();
}
void lock(){ //仅供 MutexLockGuard 调用
pthread_mutex_lock(&mutex_);
holder_ = CurrentThread::tid();
}
void unlock(){ //仅供 MutexLockGuard 调用
holder_ = 0;
pthread_mutex_unlock(&mutex_);
}
pthread_mutex_t* getPthreadMutex(){ //仅供 Condition 调用
return &mutex_;
}
private:
pthread_mutex_t mutex_;
pid_t holder_;
};
class MutexLockGuard : noncopyable{
public:
explicit MutexLockGuard(MutexLock& mutex) : mutex_(mutex){
mutex_.lock();
}
~MutexLockGuard(){
mutex_.unlock();
}
private:
MutexLock& mutex_;
};
Condition
class Condition : 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());
}
void notify(){
pthread_cond_signal(&pcond_);
}
void notifyAll(){
pthread_cond_broadcast(&pcond_);
}
// returns true if time out, false otherwise.
bool waitForSeconds(int seconds){
struct timespec abstime;
clock_gettime(CLOCK_REALTIME, &abstime);
abstime.tv_sec += static_cast<time_t>(seconds);
return ETIMEDOUT == pthread_cond_timedwait(
&pcond_, mutex_.getPthreadMutex(), &abstime);
}
private:
MutexLock& mutex_;
pthread_cond_t pcond_;
};
CountDownLatch
CountDownLatch
是一种常用且易用的同步手段,主要有两种用途:
- 主线程发起多个子线程,等这些子线程各自完成一定任务后,主线程才继续执行。通常用于主线程等待多个子线程完成初始化。
- 主线程发起多个子线程,子线程都等待主线程,主线程完成其他一些任务后,通知所有子线程开始执行。通常用于多个子线程等待主线程发出“起跑”命令
class CountDownLatch : noncopyable{
public:
//倒数几次
explicit CountDownLatch(int count) : mutex_(), condition_(mutex_), count_(count) {}
//等待计数值变为0
void wait(){
MutexLockGuard lock(mutex_);
while (count_ > 0) condition_.wait();
}
//计数减1
void countDown(){
MutexLockGuard lock(mutex_);
--count_;
if (count_ == 0) condition_.notifyAll();
}
int getCount() const {
MutexLockGuard lock(mutex_);
return count_;
}
private:
mutable MutexLock mutex_;
Condition condition_;
int count_;
};
CurrentThread
这部分的功能是获取线程标识。因为各种原因pthread_t
不适合作为线程的标识符,muduo中使用下面的函数调用的返回值作为线程的id。
pid_t gettid() { return static_cast<pid_t>(::syscall(SYS_gettid)); }
同时为了避免多次进行系统调用,使用__thread
变量来缓存gettid()的返回值,这样只有在本线程第一次调