Linux下的C/C++线程池封装

线程池的概念

为什么要引进线程池
我们原本用多线程,可以把任务丢进线程里面去,让他执行。假如这个任务执行时间很长,而且任务量很少。一个任务创建一个线程并没有什么关系。但是,如果处理的任务用时很短,且量大。由于线程创建销毁都得时间,这部分会占用了太多运行的时间,影响性能,所有需要做一些东西来改善。
大致做法
比如说,先创建5个线程(举个例子),然后让所有的线程都阻塞,添加一个任务,就往线程池里面丢任务,让里面的线程来处理这个任务,处理完又接着阻塞。这样省去了线程创建和销毁的时间。
生活中的例子
好比,你去超市买东西,要结账。普通的便利店,就一个人在收银,这就是传统的单进程,单线程。让你等得很不舒服对吧。你去了一家大型的超市,有五个柜台(一开始创建了五个线程,进入等待模式),这时候跟你一起来的有6个人(有六个任务加入),这时候五个柜台都没有人(进入阻塞状态)。然后第一个人去了一号柜台,第二个人发现一号柜台有人了,就去了二号柜台。。。。最后到了第六个人,发现前五个都有人了,他就开始排队,一发现这5个柜台有一个是空的,就冲过去算账。这就是我理解的线程池。这也许有点出入,把它换成医院叫号会更贴切。

预备知识

由于这是在linux下用c/c++写的线程池
1.C/C++
2.Linux的socket和pthread,还有pthread_mutex_t ,pthread_cond_t(不会的搜索这几个关键词,看一下就会懂了)
3.C++vector容器(看一下也就懂了)
4.Makefile(这个关系不大)

代码部分

一共有三个类:
1.NThread :封装一个线程类
2.Task : 用来存放Task任务的类
3.ThreadPoll : 线程池

NThread

传入一个线程的运行函数,和void * 参数
调用start函数开始运行线程

nthread.h

#ifndef _NTHREAD_H_
#define _NTHREAD_H_

#include <pthread.h>

class NThread
{
public:
    typedef void *(threadFun_t)(void *arg);
    NThread(threadFun_t * Fun,void *arg);
    ~NThread();
    void start();                               //线程启动
    void join();                                //等待线程结束
    static void * threadRun(void * arg);        //线程执行函数
    pthread_t getThreadId();                    //获取线程id
    bool getisStart();                          //获取是否运行状态

private:
    bool isStart;                               //判断线程是否执行
    threadFun_t * Fun;                          //user的线程函数
    void * argv;                                //arg参数
    pthread_t pthreadId;                        //线程id
};


#endif //_NTHREAD_H_

nthread.cpp

#include "nthread.h"

NThread::NThread(threadFun_t * Fun,void *arg)
{
    this->argv = arg;
    this->Fun = Fun;
    pthread_create(&this->pthreadId,NULL,this->threadRun,this);
}

NThread::~NThread()
{

}

bool NThread::getisStart()
{
    return this->isStart;
}

void * NThread::threadRun(void * arg)
{
    NThread * thread = (NThread *)arg;
    while(!thread->isStart);
    thread->Fun(thread->argv);
}

void NThread::start()
{
   this->isStart = true;
}

pthread_t NThread::getThreadId()
{
    return this->pthreadId;
}

void NThread::join()
{
    pthread_join(this->pthreadId,NULL);
}

Task

这是一个抽象类,里面必须要有一个run函数,至于run函数的参数可以,可以继承Task,然后放在类里面

task.h

#ifndef _TASK_H_
#define _TASK_H_
#include <stdio.h>
#include <unistd.h>

class Task
{
    
public:
    Task();
    ~Task();
    virtual void run() = 0;

};


#endif //_TASK_H_

task.cpp

#include "task.h"

Task::Task()
{

}

Task::~Task()
{

}

nthreadpoll

创建线程池有两个参数
1.线程最大数量
2.一开始创建线程的数量
调用AddTask就能够添加任务了

nthread_poll.h

#ifndef _THREAD_POLL_H_
#define _THREAD_POLL_H_
#include <iostream>
#include <pthread.h>
#include <vector>
#include "task.h"
#include "nthread.h"

using namespace std;

/*
*   构造函数有两个参数,(最大线程,每次新创建的线程)
*   当任务容器里面的任务是  可用的两倍就新增 $(每次新创建的线程) 的数量
*/

class ThreadPoll
{
private:
    int ThreadNum;                      //当前线程数量
    int MaxThread;                      //最大线程数量
    int CreateThread;                   //每次创建的大小
    int ActiveThread;                   //当前活跃的线程数量
    pthread_mutex_t mutex;              
    pthread_mutex_t mutexActive;
    pthread_cond_t cond;
    vector<Task *> TaskList;            //任务向量列表
    pthread_t * phtread_id;             //线程id
    vector<NThread *> NThreadList;      //NThread 对象向量列表
    bool isRun;                         //是否运行的标志位

private:
    static void * threadFunc(void * p); //线程函数
    
public:
    enum ThreadCtrl{ADD,DEL};                               //添加或者减少计数      
    ThreadPoll(int maxThread,int createThread = 4);         //构造函数 maxThread为最大的线程createThread为每次最多创建的线程
    ~ThreadPoll();                                          //析构
    void AddTask(Task * Addtask);                           //添加任务到任务向量列表
    void Destroy();                                         //结束所有线程,正在运行的等待运行
    void ChangeActiveThread(ThreadCtrl ctrl);               //改变当前占用进程的累计计数
    int GetSleepThreadNum();                                //获得可用的进程数量
};


#endif //_THREAD_POLL_H_

nthread_poll.cpp

#include "thread_poll.h"


ThreadPoll::ThreadPoll(int maxThread,int createThread)
{
    this->ThreadNum = createThread;
    this->CreateThread = createThread;
    this->MaxThread = maxThread;
    this->ActiveThread = 0;
    this->isRun = true;
    if(maxThread < createThread)
    {
        this->MaxThread = this->ThreadNum;
    }

    pthread_mutex_init(&mutex,NULL);
    pthread_mutex_init(&mutexActive,NULL);
    pthread_cond_init(&cond,NULL);
    
    this->phtread_id = new pthread_t[maxThread];
    for(int i = 0 ;i < ThreadNum;i++)
    {
        //pthread_create(&phtread_id[i],NULL,threadFunc,this);
        NThread *  nthreadCreate = new NThread(threadFunc,this);
        NThreadList.push_back(nthreadCreate);
        phtread_id[i] = nthreadCreate->getThreadId();
        nthreadCreate->start();
        cout<<"pthread "<<i<<" id : "<<phtread_id[i]<<endl;
    }
}

ThreadPoll::~ThreadPoll()
{
    delete phtread_id;
    pthread_mutex_destroy(&mutex);
    pthread_mutex_destroy(&mutexActive);
    pthread_cond_destroy(&cond);
    // for(auto it = NThreadList.begin();it !=NThreadList.end();it++)
    // {
    //     delete *it;
    //     NThreadList.erase(it);
    // }
    NThreadList.clear();
    
}

void * ThreadPoll::threadFunc(void * p)
{
    ThreadPoll *poll = (ThreadPoll *)p;
    while (1)
    {
        //判断线程退出
        if(!poll->isRun)
        {
            break;
        }

        pthread_mutex_lock(&poll->mutex);
        //如果任务列表为空,就进入等待队列
        while(poll->TaskList.size() == 0)
        {
            pthread_cond_wait(&poll->cond,&poll->mutex);
        }
        poll->ChangeActiveThread(ADD);
        auto it = poll->TaskList.begin();
        Task * getTask = *it;
        poll->TaskList.erase(it);
        pthread_mutex_unlock(&poll->mutex);
        
        cout<<"pthread task run ,thread id = "<<pthread_self()<<endl;
        getTask->run();
        poll->ChangeActiveThread(DEL);
    }
    
}

void ThreadPoll::AddTask(Task * Addtask)
{

    pthread_mutex_lock(&mutex);

    //如果任务数大于最大线程的2倍自动丢弃
    if(TaskList.size() <= 2*MaxThread)
    {
        TaskList.push_back(Addtask);
        pthread_cond_signal(&cond);
    } 
    else
    {
        printf("任务数量太大,舍弃\n");
    }
    
    
    //存在任务为可用的2倍就创建 createThread数量的线程
    if((this->MaxThread != this->TaskList.size()) &&(this->TaskList.size() >= 2*this->GetSleepThreadNum()))
    {
        int create = 0;
        if(this->ThreadNum + this->CreateThread > this->MaxThread)
        {
            create = this->MaxThread-this->ThreadNum;
        }
        else
        {
            create = this->CreateThread;
        }

        for(int i = 0 ;i < create;i++)
        {
            //pthread_create(&phtread_id[this->ThreadNum],NULL,threadFunc,this);
            NThread *  nthreadCreate = new NThread(threadFunc,this);
            NThreadList.push_back(nthreadCreate);
            phtread_id[this->ThreadNum] = nthreadCreate->getThreadId();
            nthreadCreate->start();
            cout<<"pthread "<<i+this->ThreadNum<<" id : "<<phtread_id[this->ThreadNum]<<endl;
        }
        this->ThreadNum += create;
    }
    pthread_mutex_unlock(&mutex);
}

void ThreadPoll::Destroy()
{
    this->isRun = false;
}

void ThreadPoll::ChangeActiveThread(ThreadCtrl ctrl)
{
    if(ctrl == ADD)
    {
        pthread_mutex_lock(&mutexActive);
        ActiveThread++;
        pthread_mutex_unlock(&mutexActive);
    }
    else if(ctrl == DEL)
    {
        pthread_mutex_lock(&mutexActive);
        ActiveThread--;
        pthread_mutex_unlock(&mutexActive);
    }
}

int ThreadPoll::GetSleepThreadNum()
{
    return this->ThreadNum - this->ActiveThread;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值