记linux下对线程池的学习及使用(二)--对线程池类的封装

结合了条件量,互斥量,任务基类,任务链表,这里对线程池类进行了完整的封装,并且在底部附上了线程池的一个简易测试案例。下面是封装源码

phreadpool.h

#ifndef _PTHREADPOOL_H
#define _PTHREADPOOL_H
#include <list>
#include <iostream>
#include<unistd.h>
#include "PThreadCond.h"
#include "PThreadMutex.h"
#include "Task.h"
using namespace std;

class CPThreadPool
{
public:
    CPThreadPool(int max = 20,int min = 3,int waitsec = 60);
    ~CPThreadPool();
    static void *TaskThread(void *arg);
    void AddTask(CTask *task);
    void start();
    void destory();
    void CreateThread();
private:
    bool m_stop;
    int m_maxcount;
    int m_mincount;
    int m_waitcount;
    int m_curcount;
    int m_waitsec;
    CPThreadCond m_cond;
    CPThreadCond m_taskMutex;
    list<CTask *> m_tasklist;
};
#endif

pthreadpool.cpp

构造函数

CPThreadPool::CPThreadPool(int max,int min,int waitsec)
{
    this->m_stop = false;
    this->m_maxcount = max;
    this->m_mincount = min;
    this->m_waitcount = 0;
    this->m_curcount = 0;
    this->m_waitsec = waitsec;
}

用m_waitcount记录休眠线程数,用m_curcount记录当前总线程数;
m_maxcount记录最大线程数,m_mincount记录最小线程数;
m_waitsec记录单个线程最大等待时间

析构函数

CThreadPool::~CThreadPool()
{
	destroy();
}

destroy函数

void CPThreadPool::destory()
{
    m_stop = true;
    while(m_curcount > 0)
    {
        m_cond.lock();
        m_cond.broadcast();
        m_cond.unlock();
        sleep(1);
    }
}

任务添加函数

void CPThreadPool::AddTask(CTask *task)
{
    printf("addtask\n");
    if(this->m_stop)
    {
        return;
    }
    m_taskMutex.lock();
    m_tasklist.push_back(task);
    m_taskMutex.unlock();
    m_cond.lock();
    if(m_waitcount)
    {
        m_cond.signal();
    }
    else if(m_curcount < m_maxcount)
    {
        CreateThread();
    }
    m_cond.unlock();
}

这里互斥量taskMutex的作用是保证多个被唤醒的线程在竞争tasklist任务链表时同步。

创建线程函数

void CPThreadPool::CreateThread()
{
    pthread_t tid;
    int ret = pthread_create(&tid,NULL,TaskThread,(void *)this);
    if(ret < 0)
    {
        perror("pthread create");
    }
    else
    {
        m_curcount++;
    }
}

start函数

void CThreadPool::start()
{
	m_cond.lock();
	m_bStop = false;
	m_cond.unlock();
}

工作主线程

// Work thread
void *CPThreadPool::TaskThread(void *arg)
{
    pthread_detach(pthread_self());
    CPThreadPool *pool = (CPThreadPool*)arg;
    while(1)
    {
        pool->m_cond.lock();
        if(pool->m_tasklist.empty())
        {
            if(pool->m_stop)
            {
                pool->m_curcount--;
                pool->m_cond.unlock();
                pthread_exit(NULL);
            }
            pool->m_waitcount++;
            bool bsignal = pool->m_cond.timewait(pool->m_waitsec);
            pool->m_waitcount--;
            if(!bsignal && pool->m_curcount > pool->m_mincount)
            {
                pool->m_curcount--;
                pool->m_cond.unlock();
                pthread_exit(NULL);
            }    
        }
        pool->m_cond.unlock();
        pool->m_taskMutex.lock();
        if(!pool->m_tasklist.empty())
        {
            CTask *t = pool->m_tasklist.front();
            pool->m_tasklist.pop_front();
            pool->m_taskMutex.unlock();
            t->run();
            delete t;
        }
        else
        {
            pool->m_taskMutex.unlock();
        }
    }
}

对线程池封装的简易测试

#include<iostream>
#include"./PThreadPool.h"
using namespace std;
class CMytask:public CTask
{
public:
    CMytask(int id){m_id = id;}
    ~CMytask(){}
    int run()
    {
        printf("run id is %d\n",m_id);
        sleep(1);
        return 0;
    }
    int m_id;
};
int main(int argc,char *argv[])
{
    CPThreadPool pool(100,3,60);
    int i = 0;
    for(i = 0;i<5000;i++)
    {
        CMytask *task = new CMytask(i);
        pool.AddTask(task);
    }
    sleep(10);
    return 0;
}

测试结果

记linux下对线程池的学习及使用(二)--对线程池类的封装

结果分析

由以上测试结果分析可以得知,线程池在封装完成后,调度起来十分的方便。在这里我只是新建了一个cmytask类用于打印数字i

class CMytask:public CTask
{
public:
    CMytask(int id){m_id = id;}
    ~CMytask(){}
    int run()
    {
        printf("run id is %d\n",m_id);
        sleep(1);
        return 0;
    }
    int m_id;
};

所有的打印过程都通过addtask这个接口送到线程池中即可。

    for(i = 0;i<5000;i++)
    {
        CMytask *task = new CMytask(i);
        pool.AddTask(task);
    }