引言
编写这么一个c++的http服务器,纯粹是满足多年前一个好奇心。为什么我输入链接可以打开一个网页?这背后究竟发生了什么?所以本着好事多磨的心理一点点从零写了这个http服务器。他有着以下几个特点。
1) 基于epoll的异步事件驱动框架
2) L/F线程池处理网络事件
3) 完全从零编写http服务模块
当然实现中为了研究原理,仅做了关键功能的开发,也有诸多不足之处。本着分享共同进步的心,希望看官不惜赐教。
完整源码见<https://github.com/kwansoner/panda.git>
线程池
线程池就是分配若干线程来复用处理任务,避免了不断创建销毁线程带来的重复工作,也避免了为每个连接创建一个线程的服务器设计。让我们献上类图。
可以看到我们有一个线程池基类IThreadPool。定义了一个往线程池投入任务的方法pushtask。这个任务对象可以是继承自IThreadHandle的任何子类实例。线程池执行任务时调用IThreadHandle的threadhandle函数。
class IThreadHandle
{
friend class CThreadPool;
public:
virtual ~IThreadHandle(){};
protected:
// desc: 线程池任务执行函数
// param: void
// return: void
virtual void threadhandle() = 0;
};
class IThreadPool
{
public:
virtual ~IThreadPool(){};
// desc: 往线程池放入任务
// param: handle/执行任务对象 block/是否阻塞的方式放入
// return: 0/成功返回 -1/错误
virtual int pushtask(IThreadHandle *handle, bool block = true) = 0;
};
首先是在构造函数中创建一定数量的线程,我们保存每个创建的线程的tid到vector中管理。在析构函数中进行销毁,向每个创建的线程发送cancel信号,然后等待线程退出。值得注意的是线程收到cancel信号时会在遇到取消点时退出。退出时会调用线程执行体中变量的析构函数。或者调用线程清理函数(如果安装了的话)。
void CThreadPool::create_threadpool()
{
pthread_attr_t thread_attr;
pthread_attr_init(&thread_attr);
for(size_t i = 0; i < m_threadnum; i++){
pthread_t tid = 0;
if(pthread_create(&tid, &thread_attr, process_task, (void *)this) < 0){
errsys("create thread[%d] filed\n", (int)i);
continue;
}
m_thread.push_back(tid);
}
pthread_attr_destroy(&thread_attr);
trace("create thread pool, thread number %d\n", (int)m_thread.size());
}
void CThreadPool::destroy_threadpool()
{
void *retval = NULL;
vector_tid_t::iterator itor = m_thread.begin();
for(; itor != m_thread.end(); itor++){
if(pthread_cancel(*itor) < 0 || pthread_join(*itor, &retval) < 0){
errsys("destroy thread[%d]\n", (int)(*itor));
continue;
}
}
m_thread.clear();
trace("destroy thread pool... done\n");
}
接下来我们看线程执行体,首先选出一个线程作为Leader,成为Leader后该线程设置一下标志m_hasleader。值得注意的是这里对于条件变量返回时的判断m_hasleader标志是while循环,为什么不是if判断就好了呢?那是因为条件变量存在多次返回的可能,在man手册中注意事项有解释。
当一个线程成为Leader后从队列m_taskqueue中获取任务,等取出一个任务后调用join_follwer取消m_hasleader标志,并通知其他线程可以成为Leader。然后就是去处理该任务,也就是回调对象的threadhandle函数。
void CThreadPool::promote_leader()
{
Pthread::CGuard guard(m_identify_mutex);
while(m_hasleader){ // more than one thread can return
m_befollower_cond.wait(m_identify_mutex);
}
m_hasleader = true;
}
void CThreadPool::join_follwer()
{
Pthread::CGuard guard(m_identify_mutex);
m_hasleader = false;
m_befollower_cond.signal();
}
void *CThreadPool::process_task(void * arg)
{
CThreadPool &threadpool = *(CThreadPool *)arg;
while(true){
threadpool.promote_leader();
IThreadHandle *threadhandle = NULL;
int ret = threadpool.m_taskqueue.pop(threadhandle);
threadpool.join_follwer();
if(ret == 0 && threadhandle)
threadhandle->threadhandle();
}
pthread_exit(NULL);
}
---------------------
作者:kwanson
来源:CSDN
原文:https://blog.csdn.net/kwanson/article/details/81160437
版权声明:本文为博主原创文章,转载请附上博文链接!