提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言:为什么需要线程池?
提示:这里可以添加本文要记录的大概内容:
当我们有某项工作需要调用线程执行时,需要创建线程,工作完成后销毁线程,然而创建和销毁开销较大,这时引入了线程池。
当有任务进来时存放在线程池的任务队列中存储。
线程池中维护了一定的数量的活着的工作者线程,没有任务时保持阻塞状态,有任务时去任务然后执行。
管理者线程负责管理线程池中线程数量,根据任务数量判断,线程太多了需要销毁一些,太少了需要创建。
一、线程池是什么
线程池的本质就是一个类/一种数据结构,这个类能够实现某些指定的功能
1.能够存放任务队列
2.工作线程(n个,负责从任务队列中取任务并处理(相当于消费者),
3.管理者线程(1个,管理工作者线程
提示:以下是本篇文章正文内容,下面案例可供参考
二、源码
1.threadpool.cpp
代码如下(示例):
#include "threadpool.h"
#include <iostream>
#include <string.h>
#include<pthread.h>
/*
* 线程池中某些函数已经使用mutexpool加锁,保证是互斥操作,调用者些函数时应保证mutex是打开的状态,否则会发生
* 死锁
*/
Threadpool::Threadpool(int& min, int& max)
{
//互斥锁条件变量
if ((pthread_mutex_init(&mutexPool, NULL)) != 0 || (pthread_cond_init(¬Empty, NULL)) != 0)
{
std::cout<<"mutex or cond init failed\n"<< std::endl; return;
}
minNum = min;
maxNum = max;
busyNum = 0;
exitNum = 0;
liveNum = min;
//初始化任务队列
//
taskq = new TaskQueue;
// std::cout << "taskq->taskNumber() :"<< taskq->taskNumber() << "\n" << std::endl;
workIDs.assign(maxNum, 0);
// std::cout << "workIDs.size() :" << workIDs.size() << "\n" << std::endl;
//创建线程
//manager函数,管理者线程的工作
pthread_create(&managerID, NULL, manager, this);
std::cout << "createmanagerID:"<< std::to_string(managerID )<< "\n" << std::endl;
//此处manager函数需要在threadpool类中设置为静态成员(非静态函数在类对象被创建时才有地址
//或者将函数定义在类外,用友元,(破坏了函数封装
//传入this到manager函数中,也就是创建pool对象后将对象传入到函数中
//pthread_t workid=0;
//std::cout << "workid:::" <<workid << "\n" << std::endl;
for (int ii = 0; ii < minNum; ii++) {
//work()函数,工作者线程对应的工作:不断从任务队列中取任务执行
pthread_create(&workIDs.at(ii), NULL, worker, this);
std::cout << "create son id:::::" << std::to_string(workIDs.at(ii) )<< "\n" << std::endl;
}
}
Threadpool::~Threadpool()
{
shutdown = true;
//回收管理者线程
pthread_join(managerID, NULL);
//唤醒阻塞进程自杀
for (int i = 0; i < liveNum; i++) {
pthread_cond_signal(¬Empty);
}
//释放堆内存
if (taskq) {
delete taskq;
}
pthread_mutex_destroy(&mutexPool);
pthread_cond_destroy(¬Empty);
}
int Threadpool::addTask(Task task)
{
//
// std::cout << "in addTask taskq:" << taskq->taskNumber() << "\n" << std::endl;
if (shutdown) {
std::cout << "shutdown pool" << "\n" << std::endl;
return -2;
}
//添加任务后唤醒线程,生产者
//
if (!taskq->addTask(task)) {
//printf("taskq.addtaskq,failed \n");
std::cout << "taskq.addtaskq, failed " << "\n" << std::endl;
return -1;
}
// std::cout << "out addTask taskq:www" << taskq->taskNumber() << "\n" << std::endl;
pthread_cond_signal(¬Empty);
return 0;
}
int Threadpool::getBusyNum()
{
int busyNum=0;
pthread_mutex_lock(&mutexPool);
busyNum = this->busyNum;
pthread_mutex_unlock(&mutexPool);
return busyNum;
}
int Threadpool::getAliveNum()
{
int liveNum = 0;
pthread_mutex_lock(&mutexPool);
liveNum = this->liveNum;
pthread_mutex_unlock(&mutexPool);
return liveNum;
}
void* Threadpool::worker(void* arg) //消费者
{
//传入的是pool对象,强制类型转换
Threadpool* pool = static_cast<Threadpool *>(arg);
// std::cout << "in worker shutdown_v " << pool->shutdown << "\n" << std::endl;
while (true) {
usleep(100);
//只有一个线程会进入线程池
pthread_mutex_lock(&(pool->mutexPool));
//任务队列为空!!!,阻塞工作线程
while (pool->taskq->taskNumber() == 0 && !pool->shutdown) {
//
pthread_cond_wait(&pool->notEmpty, &pool->mutexPool);
//阻塞之后判断是否销毁线程(由管理者线程赋值exitnum
if (pool->exitNum > 0) {
pool->exitNum--;
if (pool->liveNum > pool->minNum) {
pool->liveNum--;
pthread_mutex_unlock(&(pool->mutexPool));
std::cout << "thread exiting. " << pthread_self() << "\n" << std::endl;
pool->threadExit();
}
}
}
//如果线程池关闭
if (pool->shutdown) {
pthread_mutex_unlock(&(pool->mutexPool));
pool->threadExit();
}
//取任务
std::cout << "begin take task,tasksize: " << pool->taskq->taskNumber() << "\n" << std::endl;
//忙线程+1
Task task = pool->taskq->takeTask();
pool->busyNum++;
std::cout << "end take task ,tasksize:" << pool->taskq->taskNumber()<< "\n" << std::endl;
pthread_mutex_unlock(&(pool->mutexPool));
//work
std::cout << "thread" << std::to_string(pthread_self()) << "start working..." << std::endl;
task.function(task.arg);
//delete(task.arg);
task.arg = nullptr;
std::cout << "thread" << std::to_string(pthread_self()) << "end working..." << std::endl;
//忙线程-1
pthread_mutex_lock(&(pool->mutexPool));
pool->busyNum--;
pthread_mutex_unlock(&(pool->mutexPool));
}
return nullptr;
}
void* Threadpool::manager(void* arg)
{
std::cout << "in manager:" << "\n" << std::endl;
Threadpool* pool = static_cast<Threadpool*>(arg);
//std::cout << "in manager:" << "\n" << std::endl;
/// std::cout << "shutdown:" << pool->shutdown << "\n" << std::endl;
int liveNum;
int busyNum;
int queuesize;
while (!pool->shutdown) {
//每隔3s检测一次
sleep(5);
//取出任务池中任务的数量和当前线程的数量取出busy线程数
pthread_mutex_lock(&(pool->mutexPool));
//std::cout << "shutdown:" << pool->shutdown << "\n" << std::endl;
queuesize = pool->taskq->taskNumber();
pthread_mutex_unlock(&(pool->mutexPool));
//std::cout << "queuesize:" << queuesize << "\n" << std::endl;
//std::cout << "\nasdasdasdasd" << "\n" << std::endl;
liveNum = pool->getAliveNum();
busyNum = pool->getBusyNum();
//std::cout << "liveNum:" << liveNum <<"liveNum" << "\n" << std::endl;
//std::cout << "busyNum:" << busyNum << "liveNum" << "\n" << std::endl;
//添加线程
//任务个数》存活线程数&&存活数《最大线程数
if (queuesize > liveNum && liveNum < pool->maxNum) {
pthread_mutex_lock(&(pool->mutexPool));
int count = 0;
//批量添加线程NUMBER
for (int i = 0; i < pool->maxNum && count < pool->NUMBER && pool->liveNum < pool->maxNum; ++i) {
if (pool->workIDs.at(i) == 0) {
pthread_create(&pool->workIDs.at(i), NULL, worker, pool);
std::cout << "pthread_create:" << pool->workIDs.at(i) << "\n" << std::endl;
count++;
pool->liveNum++;
}
}
pthread_mutex_unlock(&(pool->mutexPool));
}
//销毁线程
// 设置信号exitnum,让工作者线程自杀
//busy*2<live && live>min
if (busyNum * 2 < liveNum && liveNum > pool->minNum) {
std::cout << "in manage_exit_thread:" << busyNum << "liveNum" << "\n" << std::endl;
pthread_mutex_lock(&(pool->mutexPool));
pool->exitNum = NUMBER;
pthread_mutex_unlock(&(pool->mutexPool));
//让工作线程自杀
for (int i = 0; i < NUMBER; ++i) {
pthread_cond_signal(&pool->notEmpty);
}
}
}
return nullptr;
}
void Threadpool::threadExit()
{
pthread_t tid = pthread_self();
for (int i = 0; i < maxNum; i++) {
if (workIDs.at(i) == tid) {
workIDs.at(i) = 0;
std::cout << "threadexit() called" << std::to_string(tid) << "exiting...\n" << std::endl;
break;
}
}
pthread_exit(&tid);//退出当前线程
}
TaskQueue::TaskQueue()
{
pthread_mutex_init(&mutexQ, NULL);
}
TaskQueue::~TaskQueue()
{
pthread_mutex_destroy(&mutexQ);
}
bool TaskQueue::addTask(Task task)
{
pthread_mutex_lock(&mutexQ);
TaskQ.push(task);
if (TaskQ.empty()) {
pthread_mutex_unlock(&mutexQ);
return false;
}
pthread_mutex_unlock(&mutexQ);
return true;
}
bool TaskQueue::addTask(callback f, void* a) {
//Task t{ f,a };
Task t(f, a);
pthread_mutex_lock(&mutexQ);
TaskQ.push(t);
if (TaskQ.empty()) {
pthread_mutex_unlock(&mutexQ);
return false;
}
pthread_mutex_unlock(&mutexQ);
return true;
}
Task TaskQueue::takeTask()
{
Task t;
pthread_mutex_lock(&mutexQ);
if (TaskQ.empty()) {
pthread_mutex_unlock(&mutexQ);
return t;
}
t = TaskQ.front();
TaskQ.pop();
pthread_mutex_unlock(&mutexQ);
return t;
}
2.threadpool.h
代码如下(示例):
#pragma once
#include <iostream>
#include <queue>
#include <vector>
#include <pthread.h>
#include <unistd.h>
using callback = void (*)(void* arg);
//任务
struct Task {
callback function;
void* arg;
Task() {
this->arg = nullptr;
function = nullptr;
}
Task(callback f, void* arg) {
this->arg = arg;
function = f;
// std::cout << "Task:task-arg:" << (this->arg) << "\n" << std::endl;
}
};
//任务队列
class TaskQueue {
private:
std::queue<Task> TaskQ;
public:
pthread_mutex_t mutexQ;
TaskQueue();
~TaskQueue();
//内部已实现加锁
bool addTask(Task task);
//内部已实现加锁
bool addTask(callback f, void* a);
//内部已实现加锁
Task takeTask();
//inline内联函数,在类
inline int taskNumber() {
if (TaskQ.empty()) {
// std::cout << "\n TaskQ.size empty:\n" << std::endl;
return 0;
}
else
return TaskQ.size();
}
};
//线程池
/*
*
static 函数/成员属于类而不是对象,一个类创建100个对象时,
共享static修饰的成员或变量,其他成员在每个对象都维护了一个新的。
*/
class Threadpool {
private:
TaskQueue* taskq; //任务队列
pthread_t managerID; //管理者线程id ,在创建线程时被初始化
std::vector<pthread_t> workIDs; //工作者线程 ,创建线程池时初始化
int minNum; //最小线程数
int maxNum; //线程池最大线程数
int exitNum; //需取消的线程数
pthread_mutex_t mutexPool; //互斥访问线程池、
pthread_cond_t notEmpty; //生产者消费者模型,条件变量
bool shutdown=false; //关闭线程池否
static const int NUMBER = 2; //线程池中增加线程时每次增NUMBER个
public:
//创建线程池、初始化
Threadpool(int& min, int& max);
~Threadpool();
int addTask(Task task);
//内部已加锁,互斥操作
int getBusyNum();
//互斥操作
int getAliveNum();
//
private:
//wroker:工作者线程将任务(回调函数、参数)从任务队列中取出,并执行,即调用Task的function函数
//静态成员函数只能访问静态成员变量,
static void* worker(void* arg);
static void* manager(void* arg);
void threadExit();
int busyNum; //在工作的线程数,(动态改变频率高,需要加锁
int liveNum;
};
三、test.cpp
示例代码如下:
#include "threadpool.h"
using namespace std;
void function(void* arg) {
int num = *(int*)arg;
printf("thread:%ld,working..num=%d", pthread_self(), num);
sleep(1);
}
int main() {
int b = 3,d=10,m=0;
int& a = b,&c=d;
Threadpool pool(a, c);
for (int i = 0; i < 100; i++) {
int* num = new int(i + 100);
m = pool.addTask(Task(function, num));
if (m<0) {
std::cout << "pool.addtask failed "<< m<<"\n" << std::endl;
return -1;
}
}
sleep(20);
return 0;
}