【C++实现HTTP服务器项目记录】线程池

一、C线程库

1. 创建线程

int pthread_create(
    pthread_t *thread,              // 传出参数,被创建线程的ID。
    const pthread_attr_t *attr,     // 线程属性,一般情况下使用默认属性,使用NULL。
    void *(*start_routine)(void *), // 函数指针,创建出的子线程执行的函数。
    void *arg                       // 作为实参传递给函数指针指向的函数。
);
注意:
- 函数原型中第三个参数的类型为函数指针,指向的线程的处理函数,其参数类型为(void *)。
- 若线程函数为类成员函数,则this指针会作为默认的参数被传进函数中,从而和线程函数的参数(void*)不能匹配,不能通过编译。
- 由于类的静态成员函数没有this指针,不会出现问题。

2. 退出线程

- 一般情况下,针对于主线程,如果想要让线程退出,且不影响到其他线程的正常运行,即不释放虚拟地址空间
void pthread_exit(
    void *retval    // 线程退出携带的数据,当前子线程的主线程会得到该数据。
);

3. 回收线程

- 如果子线程在运行,调用该函数的线程就会阻塞,子线程退出后,函数解除阻塞进行资源回收。
- 函数被调用一次,只能回收一个子线程,如果有多个子线程则需要循环进行回收。
int pthread_join(
    pthread_t thread, // 要被回收的子线程ID。
    void **retval     // 传出参数,存储pthread_exit()函数传递出的数据。
);

4. 线程分离

- 一般情况下,程序中的主线程有其他任务,如果让主线程负责子线程的资源回收, 只要子线程不退出主线程就会一直被阻塞。
- 子线程与主线程分离之后,子线程退出后其占用的内核资源就被系统的其他进程接管并回收了。
int pthread_detach(pthread_t thread);

二、实现代码

#ifndef THREADPOOL_H
#define THREADPOOL_H

#include <list>
#include <cstdio>
#include <exception>
#include <pthread.h>
#include "../lock/locker.h"
#include "../CGImysql/sql_connection_pool.h"

template <typename T>
class threadpool
{
public:
    // 构造函数
    threadpool(int actor_model, connection_pool *connPool, int thread_number = 8, int max_request = 10000);
    // 析构函数
    ~threadpool();

    // 向任务队列中插入任务
    bool append(T *request, int state);
    bool append_p(T *request);

private:
    // 工作线程运行的函数,它不断从任务队列中取出任务并执行之
    static void *worker(void *arg);
    void run();

private:
    // 线程池中的线程数
    int m_thread_number;
    // 任务队列中允许的最大任务数
    int m_max_requests;
    // 描述线程池的数组
    pthread_t *m_threads;
    // 任务队列
    std::list<T *> m_workqueue;
    // 保护任务队列的互斥锁
    locker m_queuelocker;
    // 是否有任务需要处理的信号量
    sem m_queuestat;
    // 数据库连接池指针
    connection_pool *m_connPool;
    // 并发模型选择
    int m_actor_model;
};

// 构造函数
template <typename T>
threadpool<T>::threadpool(int actor_model, connection_pool *connPool, int thread_number, int max_requests) : m_actor_model(actor_model), m_thread_number(thread_number), m_max_requests(max_requests), m_threads(NULL), m_connPool(connPool)
{
    if (thread_number <= 0 || max_requests <= 0)
        throw std::exception();
    // 线程池初始化
    this->m_threads = new pthread_t[this->m_thread_number];
    if (!this->m_threads)
        throw std::exception();
    // 循环创建线程,同时设置其回调函数worker
    for (int i = 0; i < thread_number; ++i)
    {
        if (pthread_create(this->m_threads + i, NULL, worker, this) != 0)
        {
            delete[] this->m_threads;
            throw std::exception();
        }
        // 线程分离,之后不用单独对工作线程进行回收
        if (pthread_detach(this->m_threads[i]))
        {
            delete[] this->m_threads;
            throw std::exception();
        }
    }
}

// 析构函数
template <typename T>
threadpool<T>::~threadpool()
{
    delete[] m_threads;
}

// 向任务队列中插入任务
template <typename T>
bool threadpool<T>::append(T *request, int state)
{
    /****** 加锁 ******/
    m_queuelocker.lock();

    // 任务队列中任务数 >= 任务队列中允许的最大请求数
    if (m_workqueue.size() >= m_max_requests)
    {
        /****** 解锁 ******/
        m_queuelocker.unlock();
        return false;
    }

    // 0:读; 1:写
    request->m_state = state;

    // 添加任务到任务队列
    m_workqueue.push_back(request);

    /****** 解锁 ******/
    m_queuelocker.unlock();

    // 信号量+1,提醒有任务要处理
    m_queuestat.post();

    return true;
}

template <typename T>
bool threadpool<T>::append_p(T *request)
{
    /****** 加锁 ******/
    m_queuelocker.lock();
    // 任务队列中任务数 >= 任务队列中允许的最大任务数
    if (m_workqueue.size() >= m_max_requests)
    {
        /****** 解锁 ******/
        m_queuelocker.unlock();
        return false;
    }
    // 添加任务到任务队列
    m_workqueue.push_back(request);

    /****** 解锁 ******/
    m_queuelocker.unlock();

    // 信号量+1,提醒有任务要处理
    m_queuestat.post();

    return true;
}

// 工作线程运行的函数
template <typename T>
void *threadpool<T>::worker(void *arg)
{
    // 将参数强转为线程池类类型
    threadpool *pool = (threadpool *)arg;
    // 调用run成员方法
    pool->run();
    return pool;
}

template <typename T>
void threadpool<T>::run()
{
    while (true)
    {
        // 等待信号量
        m_queuestat.wait();

        /****** 加锁 ******/
        m_queuelocker.lock();

        // 请求队列为空
        if (m_workqueue.empty())
        {
            /****** 解锁 ******/
            m_queuelocker.unlock();
            continue;
        }
        // 从任务队列中取出第一个任务
        T *request = m_workqueue.front();
        // 将任务从任务队列删除
        m_workqueue.pop_front();

        /****** 解锁 ******/
        m_queuelocker.unlock();

        if (!request)
            continue;

        // Reactor模型
        // 主线程只负责监听文件描述符上是否有事件发生,有的话立即通知工作线程。读写数据等处理逻辑均在工作线程中完成。
        if (1 == m_actor_model)
        {
            // 读
            if (0 == request->m_state)
            {
                // 将客户端请求报文读到读缓冲区
                if (request->read_once())
                {
                    request->improv = 1;
                    // 从数据库连接池拿出一个连接
                    connectionRAII mysqlcon(&request->mysql, m_connPool);
                    // 整个业务逻辑
                    request->process();
                }
                else
                {
                    request->improv = 1;
                    request->timer_flag = 1;
                }
            }
            // 写
            else
            {
                // 将响应报文从写缓冲区写出
                if (request->write())
                {
                    request->improv = 1;
                }
                else
                {
                    request->improv = 1;
                    request->timer_flag = 1;
                }
            }
        }
        // Proactor模型
        // 主线程和内核负责处理读写数据、接受新连接等I/O操作,工作线程仅负责业务逻辑。
        else
        {
            // 从数据库连接池拿出一个连接
            connectionRAII mysqlcon(&request->mysql, m_connPool);
            // 整个业务逻辑
            request->process();
        }
    }
}
#endif
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1.项目代码均经过功能验证ok,确保稳定可靠运行。欢迎下载体验!下载完使用问题请私信沟通。 2.主要针对各个计算机相关专业,包括计算机科学、信息安全、数据科学与大数据技术、人工智能、通信、物联网等领域的在校学生、专业教师、企业员工。 3.项目具有丰富的拓展空间,不仅可作为入门进阶,也可直接作为毕设、课程设计、大作业、初期项目立项演示等用途。 4.当然也鼓励大家基于此进行二次开发。在使用过程中,如有问题或建议,请及时沟通。 5.期待你能在项目中找到乐趣和灵感,也欢迎你的分享和反馈! 【资源说明】 基于C++实现的轻量级Web服务器源码+项目说明.zip 开发部署环境 操作系统: Ubuntu 16.04 编译器: g++ 5.4 版本控制: git 自动化构建: cmake 集成开发工具: CLion 编辑器: Vim 压测工具:WebBench 核心功能及技术 状态机解析HTTP请求,目前支持 HTTP GET、HEAD方法 添加定时器支持HTTP长连接,定时回调handler处理超时连接 使用 priority queue 实现的最小堆结构管理定时器,使用标记删除,以支持惰性删除,提高性能 使用epoll + 非阻塞IO + 边缘触发(ET) 实现高并发处理请求,使用Reactor编程模型 epoll使用EPOLLONESHOT保证一个socket连接在任意时刻都只被一个线程处理 使用线程池提高并发度,并降低频繁创建线程的开销 同步互斥的介绍 使用RAII手法封装互斥器(pthrea_mutex_t)、 条件变量(pthread_cond_t)等线程同步互斥机制,使用RAII管理文件描述符等资源 使用shared_ptr、weak_ptr管理指针,防止内存泄漏 下一步开发计划 添加异步日志系统,记录服务器运行状态 增加json配置文件,支持类似nginx的多网站配置 提供CGI支持 类似nginx的反向代理和负载均衡 必要时增加可复用内存池。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值