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
muduo网络库源码复现笔记(五):base库的Mutex.h和Condition.h和CoutntDownLatch.h
muduo网络库源码复现笔记(六):base库的BlockingQueue.h和BoundedBlockingQueue.h
muduo网络库源码复现笔记(七):base库的ThreadPool.h
muduo网络库源码复现笔记(八):base库的Singleton.h
ThreadLocal.h
前面我们提到过,对于一个全局变量,有时候我们需要它在每一个线程中有自己单独的实例。如果这个变量是POD类型数据(与原始C兼容的数据类型),可以用__thread来修饰。如果它不是的话POD类型,又在每一个线程中是一个单独实例,就需要进行一些处理了。我们管这样的叫做线程特定数据(TSD)。
ThreadLocal.h封装了一个类模板ThreadLocal实现这样的操作,看一下它的代码:
template<typename T>
class ThreadLocal : boost::noncopyable
{
public:
ThreadLocal()
{
pthread_key_create(&pkey_,&ThreadLocal::destructor);
}
~ThreadLocal()
{
pthread_key_delete(pkey_);
}
T& value()
{
T* perThreadValue = static_cast<T*>(pthread_getspecific(pkey_));
if(!perThreadValue)
{
T* newObj = new T();
pthread_setspecific(pkey_,newObj);
perThreadValue = newObj;
}
return *perThreadValue;
}
private:
static void destructor(void *x)
{
T* obj = static_cast<T*>(x);
typedef char T_must_be_complete_type[sizeof(x) == 0 ? -1 : 1];
delete obj;
}
private:
pthread_key_t pkey_;
};
pkey_
唯一的私有成员变量是pthread_key_t类型的pkey,使用这个变量及其配套的函数可以帮助我们实现线程的局部变量存储。下面看看配套函数的函数原型:
int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
int pthread_setspecific(pthread_key_t key, const void *value);
void *pthread_getspecific(pthread_key_t key);
int pthread_key_delete(pthread_key_t key);
pthread_key_create
这个函数用于创立pthread_key_t类型的变量。接受的参数有两个,第一个便是key,第二个是一个清理函数,用来在线程释放该线程存储的时候被调用。该函数指针可以设成 NULL ,这样系统将调用默认的清理函数。在构造函数中调用了pthread_key_create函数。
pthread_setspecific
这个函数用于设置需要局部存储的值,它有两个参数,第一个是key,第二个是需要局部存储的数据的类型。
pthread_getspecific
这个函数用于取出所存储的局部值,参数是key。
pthread_key_delete
这个函数用于销毁线程特定数据键,参数是key。类的析构函数调用了这个函数。
destructor函数
这个函数是被pthread_key_create调用,用于销毁局部存储数据。注意它的参数void* x,这个参数由局部存储变量而来。然后我们将它静态转换之后删除。同样这里也使用了检查不完全类型的技巧。
value函数
value返回了局部存储的值。首先我们使用pthread_getspecific来取值,如果得到的指针是空的,说明需要创建实例,并使用pthread_setspecific。最后赋值返回即可。