线程池代码完全注释

ThreadPool.h

#pragma once  //预处理指令,保证头文件只被编译一次
#include <deque>  
#include <string>  
#include <pthread.h>
#include <string.h>
#include <stdlib.h>

//名称空间设为lj
namespace lj
{
    //任务类
    class Task  
    {  
    public:
        Task(void* arg = NULL, const std::string taskName = "")
            : arg_(arg)
            , taskName_(taskName)
        {
        }
        //析构函数为虚函数
        virtual ~Task()
        {
        }
        //设置参数
        void setArg(void* arg)
        {
            arg_ = arg;
        }
        // 函数为纯虚函数,派生类会重写run函数
        virtual int run() = 0;

    protected:
        //main函数中将所有task的arg_统一设置为hello,world
        void*       arg_;
        std::string taskName_;
    };

    //线程池类
    class ThreadPool
    {
    public:
        //默认线程池含有10个线程
        ThreadPool(int threadNum = 10);
        ~ThreadPool();

    public:
        //向任务队列添加任务
        size_t addTask(Task *task);

        //停止线程池的运行
        void   stop();

        //获取任务队列中剩余的未运行完毕的任务数
        int    size();
        
        //线程池从任务队列中拿取一个任务
        Task*  take();

    private:
        //创建线程,默认为10个
        int createThreads();
        
        //线程执行这个例程
        static void* threadFunc(void * threadData);

    private:
        //运算符=重载,未实现
        ThreadPool& operator=(const ThreadPool&);
        //复制构造函数,未实现
        ThreadPool(const ThreadPool&);

    private:
        //设置为volatile,保证每次只从内存读取bool值
        volatile  bool              isRunning_;
        //线程池所含线程数
        int                         threadsNum_;
        //线程数组
        pthread_t*                  threads_;
        //任务队列
        std::deque<Task*>           taskQueue_;
        //互斥锁,保证任意时刻,只有一个线程访问该数据
        pthread_mutex_t             mutex_;
        //条件变量,作为信号量
        pthread_cond_t              condition_;
    };
}  

ThreadPool.cpp

#include <stdio.h>
#include <assert.h>
#include "ThreadPool.h" 

namespace lj
{
    //线程池构造函数,初始化成员数据
    ThreadPool::ThreadPool(int threadNum)
    {
        //设置为true,表示线程池正在运行
        isRunning_ = true;
        //设置线程数
        threadsNum_ = threadNum;
        //根据线程数,创建线程
        createThreads();
    }

    //线程池析构函数
    ThreadPool::~ThreadPool()
    {
        //停止线程池
        stop();
        //完成任务队列的资源释放
        for(std::deque<Task*>::iterator it = taskQueue_.begin(); it != taskQueue_.end(); ++it)
        {
            delete *it;
        }
        //清空任务队列
        taskQueue_.clear();
    }

    //创建多个线程
    int ThreadPool::createThreads()
    {
        //初始化互斥锁
        pthread_mutex_init(&mutex_, NULL);
        //初始化条件变量
        pthread_cond_init(&condition_, NULL);
        //开辟线程数组
        threads_ = (pthread_t*)malloc(sizeof(pthread_t) * threadsNum_);
        //创建指定数目的线程
        for (int i = 0; i < threadsNum_; i++)
        {
            pthread_create(&threads_[i], NULL, threadFunc, this);
        }
        return 0;
    }

    //向任务队列中添加任务,返回最新的任务队列大小
    size_t ThreadPool::addTask(Task *task)
    {
        //上锁
        pthread_mutex_lock(&mutex_);
        //将任务push进任务队列
        taskQueue_.push_back(task);
        int size = taskQueue_.size();
        //解锁
        pthread_mutex_unlock(&mutex_);
        //发送有新任务进入任务队列的信号给阻塞等待的线程
        pthread_cond_signal(&condition_);
        return size;
    }

    //终止线程池的运行
    void ThreadPool::stop()
    {
        //isRunning_为false,表示线程池已经终止,stop函数就不再继续执行下去,直接返回
        if (!isRunning_)
        {
            return;
        }

        isRunning_ = false;
        
        //唤醒所有被阻塞的线程,告知当前线程池将停止运行
        pthread_cond_broadcast(&condition_);

        for (int i = 0; i < threadsNum_; i++)
        {
            //等待全部线程结束
            pthread_join(threads_[i], NULL);
        }
        
        //释放线程数组,置空
        free(threads_);
        threads_ = NULL;

        //销毁互斥锁和条件变量
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&condition_);
    }

    //获取任务队列当前有几个任务
    int ThreadPool::size()
    {
        pthread_mutex_lock(&mutex_);
        int size = taskQueue_.size();
        pthread_mutex_unlock(&mutex_);
        return size;
    }

    //从任务队列中拿取一个任务
    Task* ThreadPool::take()
    {
        Task* task = NULL;
        
        //如果task为空,将一直循环执行
        while (!task)
        {
            pthread_mutex_lock(&mutex_);
            
            //如果任务队列为空并且线程池正在运行,将一直等待信号量condition_唤醒,并阻塞后面代码的执行,
            while (taskQueue_.empty() && isRunning_)
            {
                pthread_cond_wait(&condition_, &mutex_);
            }
            
            //再次检查线程池是否正在运行,如果没有,将解锁并退出循环
            if (!isRunning_)
            {
                pthread_mutex_unlock(&mutex_);
                
                break;
            }
            //检查任务队列是否为空,若为空,则解锁并继续循环
            else if (taskQueue_.empty())
            {
                pthread_mutex_unlock(&mutex_);
                continue;
            }

            //断言
            assert(!taskQueue_.empty());
            //获取任务队列的第一个任务
            task = taskQueue_.front();
            //弹出任务队列的第一个任务
            taskQueue_.pop_front();
            //获取任务后解锁
            pthread_mutex_unlock(&mutex_);
        }
        return task;
    }

    //线程需要执行的函数,参数arg由createThreads函数中语句提供pthread_create(&threads_[i], NULL, threadFunc, this),为线程池当前对象
    void* ThreadPool::threadFunc(void* arg)
    {
        //获取线程自身ID
        pthread_t tid = pthread_self();
        //将空指针arg显式转换为线程池指针
        ThreadPool* pool = static_cast<ThreadPool*>(arg);
        while (pool->isRunning_)
        {
            //线程池获取任务
            Task* task = pool->take();
            //检查任务指针是否为空,为空则退出循环
            if (!task)
            {
                printf("thread %lu will exit\n", tid);
                break;
            }

            assert(task);
            //任务执行run函数
            task->run();
        }
        return 0;
    }

}

main.cpp

#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include "ThreadPool.h"  
  
//MyTask公有继承Task
class MyTask: public lj::Task  
{  
public:  
    MyTask(){}
     
    //重写run函数
    virtual int run()  
    {  
        //打印
        printf("thread[%lu] : %s\n", pthread_self(), (char*)this->arg_);  
        sleep(1);  
        return 0;  
    }  
};  
  
int main()  
{  
      
    char szTmp[] = "hello world";
    
    //在栈上实例化任务对象
    MyTask taskObj;
    taskObj.setArg((void*)szTmp);

    //在栈上实例化线程池对象,设置线程数为10
    lj::ThreadPool threadPool(10);  
    
    //向任务队列中添加20个任务
    for(int i = 0; i < 20; i++)  
    {
        threadPool.addTask(&taskObj);  
    }

    while(1)  
    {  
        printf("there are still %d tasks need to process\n", threadPool.size());  
        
        //当前任务队列为空,则线程池终止执行,退出程序
        if (threadPool.size() == 0)
        {  
            threadPool.stop();
            printf("Now I will exit from main\n"); 
            exit(0);   
        }  
        sleep(8);  
    }  

    return 0;
}  

 

posted @ 2021-09-21 17:11  凝视深空  阅读(50)  评论(0编辑  收藏  举报