线程池的设计与实现

线程池的原理与实现

讲解内容

内容
这两天重点学习了线程池这种基础组件,并且自己试着手写了一份线程池的代码,在这里与大家分享一下学习成果。

1.线程池的作用

1.1线程池的优点

线程池是帮助我们管理线程的工具,它维护了多个线程,可以降低资源的消耗,提高系统的性能。并且通过使用线程池,我们开发人员可以更好的把精力放在任务代码上,而不去管线程是如何执行的,实现任务提交和执行的解耦。

1.2线程池在什么地方使用

假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。 如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。

2.线程池的工作原理

线程池主要由三个部分组:在调度器,任务队列,工作队列。线程池最开始只需要创建若干个线程并将他们以队列的形式放在工作队列之中,并且用条件变量监视任务队列,如果任务队列为空则阻塞,这样的话在所有线程创建完成后就会全部阻塞在等待任务到来的地方。之后由程序员编写任务并加入任务队列之中,就能唤醒阻塞线程,完成任务。

3.线程池的实现


#include<queue>
#include<pthread.h>
#include<stdlib.h>
using namespace std;
class njobs;
class threadpool;
typedef void NJOBCALLBACK(njobs *job); //回调函数

class njobs
{
public:
    njobs();
    NJOBCALLBACK *m_job_function;
    void *m_user_data; //任务带的数据
};

class nworkers
{
public:
    nworkers();
    ~nworkers();
    pthread_t m_thread; 
    int m_terminate; //是否终止
};

class threadpool
{
public:
    threadpool();
    int ThreadPoolCreate(int max_thread); //创建线程
    int ThreadPoolQueue(njobs *job);//任务入队
    static void *WorkerThread(void *ptr);

private:
    int m_max_thread;
    queue<njobs> m_waiting_jobs;//任务等待队列
    queue<nworkers> m_workers;//所包含的初始线程
    pthread_mutex_t m_jobs_mtx;
    pthread_cond_t m_jobs_cond;
};


//pthread_create传入的参数
struct workaddjob
{
    nworkers *worker;
    threadpool *pool;
};


```cpp
#include "threadpool.h"
#include<stdio.h>
njobs::njobs()
{
    m_job_function = NULL;
    m_user_data = NULL;
}

nworkers::nworkers()
{
    m_terminate=0;
}

nworkers::~nworkers()
{
    pthread_exit(NULL);
}



threadpool::threadpool()
{
    m_max_thread = 0;
    pthread_mutex_init(&m_jobs_mtx, NULL);
    pthread_cond_init(&m_jobs_cond, NULL);
}

void* threadpool::WorkerThread(void *ptr)
{
    workaddjob *wb = (workaddjob *)ptr;
    nworkers *curworker = wb->worker;
    threadpool *curpool = wb->pool;
    while(1)
    {
    //pthread_cond_wait前必须加锁
        pthread_mutex_lock(&curpool->m_jobs_mtx);
        while(curpool->m_waiting_jobs.empty())
        {
            if(curworker->m_terminate) break;
            //函数最终会阻塞在此处,pthread_cond_wait会先解锁,之后在唤醒时候再上锁。
            pthread_cond_wait(&curpool->m_jobs_cond,&curpool->m_jobs_mtx);
        }
        if(curworker->m_terminate)
        {
            pthread_mutex_unlock(&curpool->m_jobs_mtx);
            break;
        }
        njobs job = curpool->m_waiting_jobs.front();
        curpool->m_waiting_jobs.pop();
        pthread_mutex_unlock(&curpool->m_jobs_mtx);
        job.m_job_function(&job);
    }
}

int threadpool::ThreadPoolCreate(int max_thread)
{
    if(max_thread < 1) max_thread = 1;
    else m_max_thread=max_thread;
    //循环创建线程
    for(int i = 0;i < m_max_thread;i++)
    {
        nworkers *worker = new nworkers;
        if (worker == NULL)
        {
            perror("malloc");
            return 1;
        }
        workaddjob *wb=new workaddjob;
        wb->pool=this;
        wb->worker =worker;
        int ret = pthread_create(&worker->m_thread, NULL, this->WorkerThread, (void *)wb);
        if (ret)
        {
            perror("pthread_create");
            delete worker;
            return 1;
        }
        m_workers.push(*worker);
    }
    return 0;

}
//任务入队
int threadpool::ThreadPoolQueue(njobs *job)
{
    if(job == NULL)
    {
        perror("job add");
        return 1;
    }
    pthread_mutex_lock(&m_jobs_mtx);
    m_waiting_jobs.push(*job);
    pthread_cond_signal(&m_jobs_cond);
    pthread_mutex_unlock(&m_jobs_mtx);
    return  0;
}

//以下是测试案例
```cpp
#include <iostream>
#include<threadpool.h>
using namespace std;

#define MAX_THREAD			80
#define COUNTER_SIZE		1000

void counter(njobs *job) {

    int *index = reinterpret_cast<int *>(job->m_user_data);

    printf("index : %d, selfid : %lu\n", index, pthread_self());


}


int main(int argc, char *argv[]) {

    threadpool pool;

    pool.ThreadPoolCreate(MAX_THREAD);

    int i = 0;
    for (i = 0;i < COUNTER_SIZE;i ++) {
        njobs *job = (njobs*)malloc(sizeof(njobs));
        if (job == NULL)
        {
            perror("malloc");
            exit(1);
        }
        job->m_job_function = counter;
        job->m_user_data =reinterpret_cast<void *>(i);
        pool.ThreadPoolQueue(job);

    }
    printf("finish\n");
    getchar();
    return 0;
}

内容就是不断创建新的线程并且将数字传进去接下来让我们看看结果
线程池运行结果
可见线程池的运行是没有顺序的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值