• 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
    ", (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
    ", pthread_self());
                pthread_exit(NULL);
            }
    
            printf("tid %lu run
    ", 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
    ", 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
    ", threadPool.getTaskSize());
            if (threadPool.getTaskSize() == 0)
            {
                if (threadPool.StopAll() == -1)
                {
                    printf("Now I will exit from main
    ");
                    break;
                }
            }
            // 主线程,等待子线程执行完任务
            sleep(2);
        }
        return 0;
    }
    

    整理

    main.cpp

    #include "Thread.h"
    #include <iostream>
    
    class CMyTask: public CTask
    {
    public:
        CMyTask(){}
    
        inline int Run()
        {
    //        printf("%s
    ", (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
    ", threadPool.getTaskSize());
            if (threadPool.getTaskSize() == 0)
            {
               if (threadPool.StopAll() == -1)
               {
                   printf("Now I will exit from main
    ");
                   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
    ", pthread_self());
                pthread_exit(NULL);
            }
    
            printf("tid %lu run
    ", 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
    ", 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之前是没有多线程标准库的,而且这个实现,不支持线程个数的动态增长,创建子线程的个数与任务量有关。

  • 相关阅读:
    CSPS模拟 57
    CSPS模拟 56
    CSPS Oct目标
    CSPS模拟 55
    CSPS模拟 54
    CSPS模拟 53
    和manacher有关的乱写
    CSPS模拟 52
    CSPS模拟 51
    Git和代码规范
  • 原文地址:https://www.cnblogs.com/zhonghuasong/p/7401176.html
Copyright © 2020-2023  润新知