C++线程池总结

本文采用pthread实现线程池,有以下几个类。
CTask:任务抽象类,主要提供接口,供子类实现。
CMyTask:继承CTask实现接口
CThreadPool:线程池类,用于管理线程。
信号量:主要有两类,一个是条件信号量,主要是用于,主线程告诉子线程有新的任务到来,所以当任务队列里面为空的时候,子线程处于阻塞状态。还有一个信号量,是用于控制多个子线程对任务队列的访问的,同时只有一个子线程对任务队列进行访问。
线程池的实现:首先由线程池对象创建几个线程,创建好后调用相应的回调函数,然后子线程因为任务队列为空进入阻塞状态。
采用消费者-生产者模型,主线程负责添加任务,子线程负责获取任务,执行操作。子线程,没有任务就阻塞,主线程,有任务就激活子线程。

任务抽象类

class CTask
{
protected:
    string m_strTaskName;  /** 任务的名称 */
    void* m_ptrData;       /** 要执行的任务的具体数据 */
public:
    CTask(){}
    CTask(string taskName)
    {
        m_strTaskName = taskName;
        m_ptrData = NULL;
    }
    // 纯虚函数,相当于定义接口
    virtual int Run()= 0;
    // 因为向线程传参是采用void\* 类型,若果有多个变量,可以考虑用类或者结构体
    void SetData(void* data);    /** 设置任务数据 */

public:
    virtual ~CTask(){}
};

具体任务类

继承抽象类,实现接口

class CMyTask: public CTask
{
public:
    CMyTask(){}
    int Run()
    {
    	// 这里进行相关的操作
        printf("%s\n", (char*)this->m_ptrData);
        sleep(10);
        return 0;
    }
};

线程池类定义

/**
 * 线程池管理类的实现
 */
class CThreadPool
{
private:
    static  vector<CTask*> m_vecTaskList;     /** 任务列表 */
    static  bool shutdown;                    /** 线程退出标志 */
    int     m_iThreadNum;                     /** 线程池中启动的线程数 */
    pthread_t   *pthread_id;				   /** 线程id,用于控制线程*/

    static pthread_mutex_t m_pthreadMutex;    /** 线程同步锁 */
    static pthread_cond_t m_pthreadCond;      /** 线程同步的条件变量 */

protected:
    static void* ThreadFunc(void * threadData); /** 新线程的线程回调函数 */
    static int MoveToIdle(pthread_t tid);       /** 线程执行结束后,把自己放入到空闲线程中 */
    static int MoveToBusy(pthread_t tid);       /** 移入到忙碌线程中去 */

    int Create();          /** 创建线程池中的线程 */

public:
    CThreadPool(int threadNum = 10);  /** 默认创建十个子线程 */
    int AddTask(CTask *task);       /** 把任务添加到任务队列中 */
    int StopAll();                 /** 使线程池中的线程退出 */
    int getTaskSize();             /** 获取当前任务队列中的任务数 */
};

线程池类实现

#include "Thread.h"
#include <iostream>

void CTask::SetData(void * data)
{
    m_ptrData = data;
}

vector<CTask*> CThreadPool::m_vecTaskList;         //任务列表
bool CThreadPool::shutdown = false;

pthread_mutex_t CThreadPool::m_pthreadMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t CThreadPool::m_pthreadCond = PTHREAD_COND_INITIALIZER;

/**
 * 线程池管理类构造函数
 */
CThreadPool::CThreadPool(int threadNum)
{
    this->m_iThreadNum = threadNum;
    cout << "I will create " << threadNum << " threads" << endl;
    Create();
}

/**
 * 线程回调函数
 */
void* CThreadPool::ThreadFunc(void* threadData)
{
    pthread_t tid = pthread_self();
    while (1)
    {
    	// 因为要访问任务队列,所以要加同步锁
        pthread_mutex_lock(&m_pthreadMutex);
        while (m_vecTaskList.size() == 0 && !shutdown)
        {	
        	// 如果没有任务,那么子线程处于阻塞状态
            pthread_cond_wait(&m_pthreadCond, &m_pthreadMutex);
        }

        if (shutdown)
        {
        	// 主线程发了结束信号,那么子线程就依次退出
            pthread_mutex_unlock(&m_pthreadMutex);
            printf("thread %lu will exit\n", pthread_self());
            pthread_exit(NULL);
        }

        printf("tid %lu run\n", tid);
        vector<CTask*>::iterator iter = m_vecTaskList.begin();

        /**
        * 取出一个任务并处理之
        */
        CTask* task = *iter;
        if (iter != m_vecTaskList.end())
        {
            task = *iter;
            m_vecTaskList.erase(iter);
        }

        pthread_mutex_unlock(&m_pthreadMutex);

        task->Run(); /** 执行任务 */
        printf("tid:%lu idle\n", tid);
    } 
    return (void*)0;
}

/**
 * 往任务队列里边添加任务并发出线程同步信号
 */
int CThreadPool::AddTask(CTask *task)
{
	// 这里又对任务队列进行了访问,所以要加同步锁
    pthread_mutex_lock(&m_pthreadMutex);
    this->m_vecTaskList.push_back(task);
    pthread_mutex_unlock(&m_pthreadMutex);
    pthread_cond_signal(&m_pthreadCond);
    return 0;
}

/**
 * 创建线程
 */
int CThreadPool::Create()
{
    pthread_id = (pthread_t*)malloc(sizeof(pthread_t) * m_iThreadNum);
    for(int i = 0; i < m_iThreadNum; i++)
    {
    	// 创建线程,并设置回调函数
        pthread_create(&pthread_id[i], NULL, ThreadFunc, NULL);
    }
    return 0;
}

/**
 * 停止所有线程
 */
int CThreadPool::StopAll()
{
    /** 避免重复调用 */
    if (shutdown)
    {
        return -1;
    }
    printf("Now I will end all threads!!/n");
    /** 唤醒所有等待线程,线程池要销毁了 */
    shutdown = true;
    // 因为子线程可能都阻塞在等待任务到来阶段,所以需要广播条件信号量
    pthread_cond_broadcast(&m_pthreadCond);

    /** 阻塞等待线程退出,否则就成僵尸了 */
    for (int i = 0; i < m_iThreadNum; i++)
    {
    	// pthread_join,是等待相应的子线程结束,然后回收资源,如果子线程没有结束的话,主线程是会阻塞在这里的
    	// 所以这个方法常常用语,主线程来等待子线程执行完任务后,然后回收资源,退出
        pthread_join(pthread_id[i], NULL);
    }

    free(pthread_id);
    pthread_id = NULL;

    /** 销毁条件变量和互斥体 */
    pthread_mutex_destroy(&m_pthreadMutex);
    pthread_cond_destroy(&m_pthreadCond);

    return 0;
}

/**
 * 获取当前队列中任务数
 */
int CThreadPool::getTaskSize()
{
    return m_vecTaskList.size();
}

具体调用

int main()
{
    CMyTask taskObj = new CMyTask;

    char szTmp[] = "this is the first thread running";
    taskObj.SetData((void*)szTmp);
    CThreadPool threadPool(5);

    for(int i = 0; i < 5; i++)
    {
        threadPool.AddTask(&taskObj);
    }
    while(1)
    {
        printf("there are still %d tasks need to handle\n", threadPool.getTaskSize());
        if (threadPool.getTaskSize() == 0)
        {
            if (threadPool.StopAll() == -1)
            {
                printf("Now I will exit from main\n");
                break;
            }
        }
        // 主线程,等待子线程执行完任务
        sleep(2);
    }
    return 0;
}

整理

main.cpp

#include "Thread.h"
#include <iostream>

class CMyTask: public CTask
{
public:
    CMyTask(){}

    inline int Run()
    {
//        printf("%s\n", (char*)this->m_ptrData);
        sleep(10);
        return 0;
    }
};

int main()
{
    CMyTask taskObj;

    char szTmp[] = "this is the first thread running";
    taskObj.SetData((void*)szTmp);
    CThreadPool threadPool(5);

    for(int i = 0; i < 5; i++)
    {
        threadPool.AddTask(&taskObj);
    }
    while(1)
    {
        printf("there are still %d tasks need to handle\n", threadPool.getTaskSize());
        if (threadPool.getTaskSize() == 0)
        {
           if (threadPool.StopAll() == -1)
           {
               printf("Now I will exit from main\n");
               break;
           }
        }
        sleep(2);
    }

    return 0;
}

Thread.h

#ifndef __THREAD_H
#define __THREAD_H

#include <vector>
#include <string>
#include <pthread.h>

using namespace std;

/**
 * 执行任务的类,设置任务数据并执行
 */
class CTask
{
protected:
    string m_strTaskName;  /** 任务的名称 */
    void* m_ptrData;       /** 要执行的任务的具体数据 */
public:
    CTask(){}
    CTask(string taskName)
    {
        m_strTaskName = taskName;
        m_ptrData = NULL;
    }
    virtual int Run()= 0;
    void SetData(void* data);    /** 设置任务数据 */

public:
    virtual ~CTask(){}
};

/**
 * 线程池管理类的实现
 */
class CThreadPool
{
private:
    static  vector<CTask*> m_vecTaskList;     /** 任务列表 */
    static  bool shutdown;                    /** 线程退出标志 */
    int     m_iThreadNum;                     /** 线程池中启动的线程数 */
    pthread_t   *pthread_id;

    static pthread_mutex_t m_pthreadMutex;    /** 线程同步锁 */
    static pthread_cond_t m_pthreadCond;      /** 线程同步的条件变量 */

protected:
    static void* ThreadFunc(void * threadData); /** 新线程的线程回调函数 */
    static int MoveToIdle(pthread_t tid);       /** 线程执行结束后,把自己放入到空闲线程中 */
    static int MoveToBusy(pthread_t tid);       /** 移入到忙碌线程中去 */

    int Create();          /** 创建线程池中的线程 */

public:
    CThreadPool(int threadNum = 10);
    int AddTask(CTask *task);      /** 把任务添加到任务队列中 */
    int StopAll();                 /** 使线程池中的线程退出 */
    int getTaskSize();             /** 获取当前任务队列中的任务数 */
};

#endif

Thread.cpp

#include "Thread.h"
#include <iostream>

void CTask::SetData(void * data)
{
    m_ptrData = data;
}

vector<CTask*> CThreadPool::m_vecTaskList;         //任务列表
bool CThreadPool::shutdown = false;

pthread_mutex_t CThreadPool::m_pthreadMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t CThreadPool::m_pthreadCond = PTHREAD_COND_INITIALIZER;

/**
 * 线程池管理类构造函数
 */
CThreadPool::CThreadPool(int threadNum)
{
    this->m_iThreadNum = threadNum;
    cout << "I will create " << threadNum << " threads" << endl;
    Create();
}

/**
 * 线程回调函数
 */
void* CThreadPool::ThreadFunc(void* threadData)
{
    pthread_t tid = pthread_self();
    while (1)
    {
        pthread_mutex_lock(&m_pthreadMutex);
        while (m_vecTaskList.size() == 0 && !shutdown)
        {
            pthread_cond_wait(&m_pthreadCond, &m_pthreadMutex);
        }

        if (shutdown)
        {
            pthread_mutex_unlock(&m_pthreadMutex);
            printf("thread %lu will exit\n", pthread_self());
            pthread_exit(NULL);
        }

        printf("tid %lu run\n", tid);
        vector<CTask*>::iterator iter = m_vecTaskList.begin();

        /**
        * 取出一个任务并处理之
        */
        CTask* task = *iter;
        if (iter != m_vecTaskList.end())
        {
            task = *iter;
            m_vecTaskList.erase(iter);
        }

        pthread_mutex_unlock(&m_pthreadMutex);

        task->Run(); /** 执行任务 */
        printf("tid:%lu idle\n", tid);
    } 
    return (void*)0;
}

/**
 * 往任务队列里边添加任务并发出线程同步信号
 */
int CThreadPool::AddTask(CTask *task)
{
    pthread_mutex_lock(&m_pthreadMutex);
    this->m_vecTaskList.push_back(task);
    pthread_mutex_unlock(&m_pthreadMutex);
    pthread_cond_signal(&m_pthreadCond);
    return 0;
}

/**
 * 创建线程
 */
int CThreadPool::Create()
{
    pthread_id = (pthread_t*)malloc(sizeof(pthread_t) * m_iThreadNum);
    for(int i = 0; i < m_iThreadNum; i++)
    {
        pthread_create(&pthread_id[i], NULL, ThreadFunc, NULL);
    }
    return 0;
}

/**
 * 停止所有线程
 */
int CThreadPool::StopAll()
{
    /** 避免重复调用 */
    if (shutdown)
    {
        return -1;
    }
    printf("Now I will end all threads!!/n");
    /** 唤醒所有等待线程,线程池要销毁了 */
    shutdown = true;
    pthread_cond_broadcast(&m_pthreadCond);

    /** 阻塞等待线程退出,否则就成僵尸了 */
    for (int i = 0; i < m_iThreadNum; i++)
    {
        pthread_join(pthread_id[i], NULL);
    }

    free(pthread_id);
    pthread_id = NULL;

    /** 销毁条件变量和互斥体 */
    pthread_mutex_destroy(&m_pthreadMutex);
    pthread_cond_destroy(&m_pthreadCond);

    return 0;
}

/**
 * 获取当前队列中任务数
 */
int CThreadPool::getTaskSize()
{
    return m_vecTaskList.size();
}

不足

本文采用的是pthread实现C++多线程,因为C++11之前是没有多线程标准库的,而且这个实现,不支持线程个数的动态增长,创建子线程的个数与任务量有关。

原文链接: https://www.cnblogs.com/zhonghuasong/p/7401176.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    C++线程池总结

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/258624

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月14日 上午11:53
下一篇 2023年2月14日 上午11:57

相关推荐