【C++】线程池的作用及实现

目录

  • 一、简介
      • 池式结构
      • 线程池
      • 线程池中比较关键的东西
    • 实现代码

参考文章:C/C++手撕线程池(线程池的封装和实现)

一、简介

池式结构

  • 在计算机体系结构中有许多池式结构:内存池、数据库连接池、请求池、消息队列、对象池等等。
  • 池式结构解决的主要问题为缓冲问题,起到的是缓冲区的作用。

线程池

  通过使用线程池,我们可以有效降低多线程操作中任务申请和释放产生的性能消耗。特别是当我们每个线程的任务处理比较快时,系统大部分性能消耗都花在了pthread_create以及释放线程的过程中。那既然是这样的话,何不在程序开始运行阶段提前创建好一堆线程,等我们需要用的时候只要去这一堆线程中领一个线程,用完了再放回去,等程序运行结束时统一释放这一堆线程呢?按照这个想法,线程池出现了。

线程池中比较关键的东西

  若想自己编写一个线程池框架,那么可以先关注线程池中比较关键的东西:

  • 工作队列
  • 任务队列
  • 线程池的池
  • pthread_create中的回调函数
    【C++】线程池的作用及实现_第1张图片
      如图所示,我们将整个框架以及任务添加接口定义为线程池的“池”,那么在这个池子中重要的就是工作队列、任务队列、以及决定工作队列中的thread到底应该工作还是休息的回调函数。

实现代码

#include 
#include 
#include 
#include 
#include 
#include 
#include   // 包含 atoi 函数

class ThreadPool{
private:
    struct NWORKER{
        pthread_t threadid;
        bool terminate;
        int isWorking;
        ThreadPool *pool;
    } *m_workers;

    struct NJOB{
        void (*func)(void *arg);     //任务函数
        void *user_data;
    };

public:
    //线程池初始化
    //numWorkers:线程数量
    ThreadPool(int numWorkers, int max_jobs);
    //销毁线程池
    ~ThreadPool();
    //面向用户的添加任务
    int pushJob(void (*func)(void *data), void *arg, int len);

private:
    //向线程池中添加任务
    bool _addJob(NJOB* job);
    //回调函数
    static void* _run(void *arg);
    void _threadLoop(void *arg);

private:
    std::list<NJOB*> m_jobs_list;
    int m_max_jobs;							//任务队列中的最大任务数
    int m_sum_thread;						//worker总数
    int m_free_thread;						//空闲worker数
    pthread_cond_t m_jobs_cond;           //线程条件等待
    pthread_mutex_t m_jobs_mutex;         //为任务加锁防止一个任务被两个线程执行等其他情况
};

//run为static函数
void* ThreadPool::_run(void *arg) {
    NWORKER *worker = (NWORKER *)arg;
    worker->pool->_threadLoop(arg);
}

//threadLoop为普通成员函数
void ThreadPool::_threadLoop(void *arg) {
    NWORKER *worker = (NWORKER*)arg;
    while (1){
        //线程只有两个状态:执行\等待
        //查看任务队列前先获取锁
        pthread_mutex_lock(&m_jobs_mutex);
        //当前没有任务
        while (m_jobs_list.size() == 0) {
        	//检查worker是否需要结束生命
            if (worker->terminate) break;
            //条件等待直到被唤醒
            pthread_cond_wait(&m_jobs_cond,&m_jobs_mutex);
        }
        //检查worker是否需要结束生命
        if (worker->terminate){
            pthread_mutex_unlock(&m_jobs_mutex);
            break;
        }
        //获取到job后将该job从任务队列移出,免得其他worker过来重复做这个任务
        struct NJOB *job = m_jobs_list.front();
        m_jobs_list.pop_front();
		//对任务队列的操作结束,释放锁
        pthread_mutex_unlock(&m_jobs_mutex);

        m_free_thread--;
        worker->isWorking = true;
        //执行job中的func
        job->func(job->user_data);
        worker->isWorking = false;

        free(job->user_data);
        free(job);
    }

    free(worker);
    pthread_exit(NULL);
}

bool ThreadPool::_addJob(NJOB *job) {
	//尝试获取锁
    pthread_mutex_lock(&m_jobs_mutex);
    //判断队列是否超过任务数量上限
    if (m_jobs_list.size() >= m_max_jobs){
        pthread_mutex_unlock(&m_jobs_mutex);
        return false;
    }
    //向任务队列添加job
    m_jobs_list.push_back(job);
    //唤醒休眠的线程
    pthread_cond_signal(&m_jobs_cond);
    //释放锁
    pthread_mutex_unlock(&m_jobs_mutex);
	return true;
}

//面向用户的添加任务
int ThreadPool::pushJob(void (*func)(void *), void *arg, int len) {
    struct NJOB *job = (struct NJOB*)malloc(sizeof(struct NJOB));
    if (job == NULL){
        perror("malloc");
        return -2;
    }
    memset(job, 0, sizeof(struct NJOB));
    job->user_data = malloc(len);
    memcpy(job->user_data, arg, len);
    job->func = func;
    _addJob(job);

    return 1;
}

ThreadPool::ThreadPool(int numWorkers, int max_jobs = 10) : m_sum_thread(numWorkers), m_free_thread(numWorkers), m_max_jobs(max_jobs){   //numWorkers:线程数量
    if (numWorkers < 1 || max_jobs < 1){
        perror("workers num error");
    }
    //初始化jobs_cond
    if (pthread_cond_init(&m_jobs_cond, NULL) != 0)
        perror("init m_jobs_cond fail\n");

    //初始化jobs_mutex
    if (pthread_mutex_init(&m_jobs_mutex, NULL) != 0)
        perror("init m_jobs_mutex fail\n");

    //初始化workers
    m_workers = new NWORKER[numWorkers];
    if (!m_workers){
        perror("create workers failed!\n");
    }

	//初始化每个worker
    for (int i = 0; i < numWorkers; ++i){
        m_workers[i].pool = this;
        int ret = pthread_create(&(m_workers[i].threadid), NULL, _run, &m_workers[i]);
        if (ret){
            delete[] m_workers;
            perror("create worker fail\n");
        }
        if (pthread_detach(m_workers[i].threadid)){
            delete[] m_workers;
            perror("detach worder fail\n");
        }
        m_workers[i].terminate = 0;
    }
}

ThreadPool::~ThreadPool(){
	//terminate值置1
    for (int i = 0; i < m_sum_thread; i++){
        m_workers[i].terminate = 1;
    }
    //广播唤醒所有线程
    pthread_mutex_lock(&m_jobs_mutex);
    pthread_cond_broadcast(&m_jobs_cond);
    pthread_mutex_unlock(&m_jobs_mutex);
    delete[] m_workers;
}

#include "thread_pool.h"

void testFun(void* arg){
    printf("i = %d\n", *(int *)arg);
}


int main(){
    ThreadPool *pool = new ThreadPool(1000, 2000);

    printf("线程池初始化成功\n");
    int i = 0;
    for (i = 0; i < 1000; ++i) {
        pool->pushJob(testFun, &i, sizeof(int));
    }
}

你可能感兴趣的:(c++,java,开发语言)