以前做均衡负载的时候就想写过线程池,那时候没有很理解就没写,最近尝试自己搭个高并发的小型服务器,又学习了下线程池,但感觉网上的大多涉及的技术点比较多,对于初学者不容易理解,这里我也分享下我自己写的简易线程池,调试环境在Ubuntu18.04。
该线程池通过设置任务函数(搬运工)不断地访问等待队列,让所有子线程均执行该任务函数,只要有任务就取出执行。新增的任务以函数+参数的形式封装推入任务队列。当要销毁线程池时,将队列容量置零并等待所有任务完成即销毁线程数组。
该线程池的特点是简单易用,线程无需频繁创建销毁的开销,但为便于理解没有做安全性封装。
以下直接芳代码,注释比较详细,应该很容易理解。
//thread.h
#ifndef THREAD_H_
#define THREAD_H_
#include <pthread.h>
#include <queue>
#include <semaphore.h>
using namespace std;
typedef void (*pfunc)(void* ); //定义函数指针pfunc
struct pf //封装函数指针与参数
{
pfunc fun;
void* arg;
};
class thread_pool
{
private:
sem_t m_sem; //信号量
pthread_mutex_t m_mutex1; //锁1
pthread_mutex_t m_mutex2; //锁2
int max_thread; //线程数量
int busy_thread; //在忙线程数量
int busy_task; //未完成任务数量
queue<pf> wait_queue; //等待任务队列
int max_wait; //队列上限
pthread_t* thread_arr; //线程数组
static void* worker(void* arg); //与pthread_create进行类型匹配,其中static必要
public:
thread_pool(int m_th,int w_th);
~thread_pool();
bool add_task(pfunc pfc,void* arg); //添加任务
void close_pool(); //关闭线程池
};
#endif
//thread.cpp
#include <iostream>
#include "thread.h"
using namespace std;
void* thread_pool::worker(void* arg) //工作线程
{
thread_pool* p=(thread_pool*) arg; //将传入的对象转化类型
while(1)
{
sem_wait(&p->m_sem); //如果任务队列无任务,信号量为0,阻塞线程
pthread_mutex_lock(&p->m_mutex1); //以下领取任务,防止竞争
if(p->wait_queue.empty()) //确保有任务可领取
{
cout<<"任务丢失"<<endl;
pthread_mutex_unlock(&p->m_mutex1);
continue;
}
p->busy_thread++; //忙线程+1
struct pf tmp=p->wait_queue.front();
p->wait_queue.pop(); //取出任务
pthread_mutex_unlock(&p->m_mutex1);
tmp.fun(tmp.arg); //执行任务,这里一般不进行阻塞
pthread_mutex_lock(&p->m_mutex2); //防止竞争
p->busy_thread--; //忙线程-1
p->busy_task--; //忙任务-1
cout<<"完成任务"<<endl;
pthread_mutex_unlock(&p->m_mutex2);
}
};
thread_pool::thread_pool(int m_th,int w_th):max_thread(m_th),busy_thread(0),max_wait(w_th),busy_task(0)
{
thread_arr=new pthread_t[max_thread]; //创建线程数组
pthread_mutex_init(&m_mutex1,NULL); //初始化2把线程锁
pthread_mutex_init(&m_mutex2,NULL);
sem_init(&m_sem,0,0); //初始化信号量
for(int i=0;i<max_thread;i++){ //创建线程并分离线程,线程各自执行
pthread_create(thread_arr+i,NULL,worker,this);
pthread_detach(thread_arr[i]);
}
};
thread_pool::~thread_pool()
{
if (thread_arr)delete []thread_arr; //销毁线程数组
}
bool thread_pool::add_task(pfunc pfc,void* arg)
{
pthread_mutex_lock(&m_mutex1); //添加任务,防止竞争
if(wait_queue.size()<max_wait) //等待队列还未满
{
pf newpf={fun:pfc,arg:arg};
wait_queue.push(newpf); //将任务函数与参数加入
busy_task++;
pthread_mutex_unlock(&m_mutex1);
sem_post(&m_sem); //任务增加,信号量+1
return true;
}
cout<<"队列已满"<<endl;
pthread_mutex_unlock(&m_mutex1);
return false;
};
void thread_pool::close_pool()
{
max_wait=0; //不允许再添加任务
while(busy_task>0); //等待知道任务全都处理完
}
//main.cpp
#include <iostream>
#include "thread.h"
using namespace std;
void work1(void* arg)
{
int n=*(int*) arg;
int sum=0;
for(int i=0;i<1000*n;i++)
{
sum+=i;
}
printf("%d",sum);
}
int main()
{
thread_pool tp(4,5); //创建线程数4,队列长度5的线程池
int tmp[10];
for(int i=0;i<10;i++)
{
tmp[i]=i;
tp.add_task(work1,tmp+i); //连续添加10次任务
}
tp.close_pool();
return 0;
}
//Makefile
FLAG = ${F}
main: main.cpp thread.cpp
g++ main.cpp thread.cpp -o main ${FLAG} -lpthread
如果有问题与改进的地方也希望小伙伴们指正!