线程池代码完全注释
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; }