线程池的简单实现
文章目录
一 线程池的定义
线程池就是有一堆已经创建好了的线程,初始都处于空闲等待状态,当有新的任务需要处理的时候,就从这堆线程(线程池)中取一个空闲等待的线程来处理任务,当任务处理完毕后,就再次把该线程放回池中(一般就是将线程状态置为空闲),以供后面的任务继续使用。当池子里的线程全都处于忙碌状态时,线程池中没有可用的空闲等待线程,此时根据需要选择创建一个新的线程并置入池中,或者通知任务当前线程池里所有线程都在忙,等待片刻再尝试。
二 使用线程池的原因
线程池的好处就在于线程复用。某个线程在处理完一个任务后,可以继续处理下一个任务,而不用销毁后再创建,这样可以避免无谓的开销,因此尤其适用于连续产生大量并发任务的场合。
三 用C++实现一个简单的线程池
3.1 thread_pool.h
#ifndef LINUXPRO_THREAD_POOL_H
#include <vector>
#include <string>
#include <pthread.h>
using namespace std;
/*执行任务的类:设置任务数据并执行*/
class Task
{
protected:
string m_taskName;
void *m_data; // 任务数据
public:
Task() = default;
Task(string &taskName) : m_taskName(taskName), m_data(NULL) {}
virtual int Run() = 0;
void SetData(void *data); // 设置任务数据
virtual ~Task() {}
};
/*线程池管理类*/
class ThreadPool
{
private:
static vector<Task *> m_taskList; // 任务列表
static bool m_shutDown; // 线程退出标志
int m_threadNum; // 线程池中启动的线程数
pthread_t *m_pthreadId;
static pthread_mutex_t m_pthreadMutex; // 线程同步锁
static pthread_cond_t m_pthreadCond; // 线程同步条件变量
protected:
static void* ThreadFun(void *threadData); // 新线程的线程回调函数
static int MoveToIdle(pthread_t threadId); // 线程执行结束后,把自己放入空闲线程中
static int MoveToBusy(pthread_t threadId); // 移入线程到忙碌线程中
int Create(); // 创建线程池中的线程
public:
ThreadPool(int threadNum);
int AddTask(Task *task); // 把任务添加到任务队列中
int StopAll(); // 使线程池中的所有线程退出
int GetTaskSize(); // 获取当前任务队列中的任务数
};
#define LINUXPRO_THREAD_POOL_H
#endif //LINUXPRO_THREAD_POOL_H
3.2 thread_pool.cpp
#include <cstdio>
#include "thread_pool.h"
void Task::SetData(void *data)
{
m_data = data;
}
// 静态成员初始化
vector<Task *> ThreadPool::m_taskList;
bool ThreadPool::m_shutDown = false;
pthread_mutex_t ThreadPool::m_pthreadMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t ThreadPool::m_pthreadCond = PTHREAD_COND_INITIALIZER;
// 线程池构造函数
ThreadPool::ThreadPool(int threadNum)
{
this->m_threadNum = threadNum;
printf("it will create %d threads.\n", threadNum);
Create();
}
// 线程回调函数
void* ThreadPool::ThreadFun(void *threadData)
{
pthread_t threadId = pthread_self();
while (1)
{
pthread_mutex_lock(&m_pthreadMutex);
// 如果队列为空,等待新的任务进入队列
while (0 == m_taskList.size() && !m_shutDown)
{
pthread_cond_wait(&m_pthreadCond, &m_pthreadMutex);
}
// 关闭线程
if (m_shutDown)
{
pthread_mutex_unlock(&m_pthreadMutex);
printf("[threadId:%lu]\texit\n", pthread_self());
pthread_exit(NULL);
}
printf("[threadId:%lu]\tturn:\n", threadId);
vector<Task *>::iterator iter = m_taskList.begin();
// 取出一个任务并处理
Task *task = *iter;
if (m_taskList.end() != iter)
{
task = *iter;
m_taskList.erase(iter);
}
pthread_mutex_unlock(&m_pthreadMutex);
task->Run(); // 执行任务
printf("[threadId:%lu]\tidle:\n", threadId);
}
return (void *)0;
}
// 往任务队列里添加并发出线程同步信号
int ThreadPool::AddTask(Task *task)
{
pthread_mutex_lock(&m_pthreadMutex);
m_taskList.push_back(task);
pthread_mutex_unlock(&m_pthreadMutex);
pthread_cond_signal(&m_pthreadCond);
return 0;
}
// 创建线程
int ThreadPool::Create()
{
m_pthreadId = new pthread_t[m_threadNum];
for (int i = 0; i < m_threadNum; i++)
{
pthread_create(&m_pthreadId[i], NULL, ThreadFun, NULL);
}
return 0;
}
// 停止所有线程
int ThreadPool::StopAll()
{
// 避免重复
if (m_shutDown)
{
return -1;
}
printf("Now it will end all threads!\n\n");
// 唤醒所有等待线程,线程池也要销毁了
m_shutDown = true;
pthread_cond_broadcast(&m_pthreadCond);
for (int i = 0; i < m_threadNum; i++)
{
pthread_join(m_pthreadId[i], NULL);
}
// 清理僵尸线程
delete[](m_pthreadId);
m_pthreadId = NULL;
// 销毁互斥锁和条件变量
pthread_mutex_destroy(&m_pthreadMutex);
pthread_cond_destroy(&m_pthreadCond);
return 0;
}
// 获取当前任务队列中的任务数
int ThreadPool::GetTaskSize()
{
return m_taskList.size();
}
3.3 thread_pool_use.cpp
#include <cstdio>
#include <stdlib.h>
#include <unistd.h>
#include "thread_pool.h"
class MyTask : public Task
{
public:
MyTask() = default;
int Run()
{
printf("%s\n", (char *)m_data);
sleep(1);
return 0;
}
~MyTask() {}
};
int main()
{
MyTask taskObj;
char str[] = "hello!";
taskObj.SetData((void *)str);
ThreadPool threadPool(5); // 线程池大小为5
for (int i = 0; i < 10; i++)
{
threadPool.AddTask(&taskObj);
}
while (1)
{
printf("There are still %d tasks need to handle\n", threadPool.GetTaskSize());
// 任务队列已经没有任务了
if (0 == threadPool.GetTaskSize())
{
// 清除线程池
if (-1 == threadPool.StopAll())
{
printf("Thread pool clear, eixt.\n");
exit(0);
}
}
sleep(2);
printf("2 seconds later...\n");
}
return 0;
}
3.4 编译生成 test 可执行程序
g++ thread_pool.cpp thread_pool_use.cpp -o test -lpthread -std=c++11
3.5 输出结果
it will create 5 threads.
There are still 10 tasks need to handle
[threadId:140571464595200] turn:
hello!
[threadId:140571456202496] turn:
hello!
[threadId:140571489773312] turn:
hello!
[threadId:140571481380608] turn:
hello!
[threadId:140571472987904] turn:
hello!
[threadId:140571489773312] idle:
[threadId:140571489773312] turn:
hello!
[threadId:140571472987904] idle:
[threadId:140571472987904] turn:
hello!
[threadId:140571456202496] idle:
[threadId:140571456202496] turn:
hello!
[threadId:140571481380608] idle:
[threadId:140571481380608] turn:
hello!
[threadId:140571464595200] idle:
[threadId:140571464595200] turn:
hello!
2 seconds later...
There are still 0 tasks need to handle
Now it will end all threads!
[threadId:140571489773312] idle:
[threadId:140571489773312] exit
[threadId:140571472987904] idle:
[threadId:140571472987904] exit
[threadId:140571456202496] idle:
[threadId:140571456202496] exit
[threadId:140571481380608] idle:
[threadId:140571481380608] exit
[threadId:140571464595200] idle:
[threadId:140571464595200] exit
2 seconds later...
There are still 0 tasks need to handle
Thread pool clear, eixt.