线程池这个概念在之前的文章中曾经多次谈及过,但每次都是浅尝辄止,从来没有实现过。因为感觉这个东西很高深莫测,觉得自己很难实现。但是通过这几天的研究,决定在这篇文章中尝试实现一下线程池,如果大家没有看到这篇文章,那就是说明实现失败了。
什么是线程池?
线程池的概念在之前的文章中曾经多次的讲解过,线程池就是为了解决线程在程序中因频繁创建和销毁而消耗大量时间而存在的。它可以有效的控制程序中线程的数量,尤其是在需要处理大量短任务的情况下,更是鲜有成效。
即在程序开始正式任务之前,先创建出一些线程,这些线程在程序不会被销毁,而且程序在运行中也不会再去创建线程。这样在程序的运行期间就提高了效率。
思路:先创建出一组线程,利用条件变量将线程阻塞。一旦任务队列向任务队列中添加了任务,则唤醒一个线程取执行该任务。如果此时任务队列中有任务但无线程,则任务等待执行线程结束后再取执行。
简单线程池实现
实现功能:创建线程池、添加任务、销毁线程池。
运行环境:CentOS7.0虚拟机
语言:pthread库+c
编译器:gcc
(如有大神看出错误,请及时斧正,以免让更多人误解。)
threadPool.h
#ifndef THREADPOOL
#define THREADPOOL
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/types.h>
enum threadPoolFlag{RUN=0,END=1};
typedef enum threadPoolFlag TPF;
//任务节点
struct TaskQueue
{
void* (*fun)(void*);
void* agrv;
struct TaskQueue* next;
};
typedef struct TaskQueue TAQ;
struct ThreadPool
{
TPF flag; //线程池存在的标志
TAQ *taskHead; //任务队列头指针
pthread_cond_t taskCond; //任务条件
pthread_mutex_t taskMutex; //任务互斥锁
pthread_t *threadID; //线程ID号
int maxThreadNum; //线程池中最大线程数
int curThreadNum; //线程池中活跃线程数
int curTaskNum; //当前任务数
};
typedef struct ThreadPool THP;
//防止外部文件失误调用。(必须调用函数返回)
static THP *threadPool=NULL;
//创建线程池
//参数说明:需要创建的线程总数目
THP* createThreadPool(int threadNum);
//处理线程函数
void* threadHeadle(void* argv);
//向任务队列中添加新任务,线程自动执行
//参数说明:需要执行的函数指针;函数参数
void addTask(void* (*fun)(void*),void* argv);
//销毁线程池
void destroyThreadPool();
#endif
threadPool.c
#include "threadPool.h"
void* threadHeadle(void* argv)
{
while(threadPool->flag==RUN)
{
pthread_mutex_lock(&(threadPool->taskMutex));
//如果线程池处于运行中,且任务队列中无任务,则线程睡眠等待被唤醒。
while(threadPool->flag==RUN && threadPool->curTaskNum==0)
{
//等待任务来时被唤醒
pthread_cond_wait(&(threadPool->taskCond),&(threadPool->taskMutex));
}
//执行任务队列中的任务
if(threadPool->flag==RUN)
{
//领取任务
TAQ *p=threadPool->taskHead;
threadPool->taskHead=threadPool->taskHead->next;
//任务数减1
--threadPool->curTaskNum;
//活跃线程数加1
++threadPool->curThreadNum;
pthread_mutex_unlock(&(threadPool->taskMutex));
//执行任务
(*(p->fun))(p->agrv);
free(p);
p=NULL;
//存在没有同步的风险
--threadPool->curThreadNum;
}
//销毁线程池
else if(threadPool->flag==END)
{
--threadPool->maxThreadNum;
pthread_mutex_unlock(&(threadPool->taskMutex));
pthread_detach(pthread_self());
pthread_exit(NULL);
}
}
}
THP* createThreadPool(int threadNum)
{
threadPool=(THP*)malloc(sizeof(THP));
threadPool->flag=RUN;
pthread_mutex_init(&(threadPool->taskMutex),NULL);
pthread_cond_init(&(threadPool->taskCond),NULL);
threadPool->maxThreadNum=threadNum;
threadPool->curThreadNum=0;
threadPool->curTaskNum=0;
threadPool->threadID=(pthread_t*)malloc(threadNum*sizeof(pthread_t));
int i=0;
for(;i<threadNum;++i)
{
pthread_create(&(threadPool->threadID[i]),NULL,threadHeadle,NULL);
}
return threadPool;
}
void addTask(void* (*fun)(void*),void* argv)
{
//将新来的任务,插入任务队列的头节点的位置。
TAQ *newTask=(TAQ*)malloc(sizeof(TAQ));
newTask->fun=fun;
newTask->agrv=argv;
newTask->next=threadPool->taskHead;
threadPool->taskHead=newTask;
pthread_mutex_lock(&(threadPool->taskMutex));
//任务队列中任务数加1。
++threadPool->curTaskNum;
//当线程池还有任务时,唤醒线程池中的一个睡眠线程,去执行任务。
if(threadPool->curThreadNum<threadPool->maxThreadNum)
{
pthread_cond_signal(&(threadPool->taskCond));
}
pthread_mutex_unlock(&(threadPool->taskMutex));
}
void destroyThreadPool()
{
if(threadPool->flag==RUN)
{
threadPool->flag=END;
pthread_cond_broadcast(&(threadPool->taskCond));
TAQ *p=threadPool->taskHead;
while(p)
{
--threadPool->curTaskNum;
threadPool->taskHead=threadPool->taskHead->next;
free(p);
p=threadPool->taskHead;
}
}
}
void* testFun(void* argv)
{
int *p= (int*)argv;
printf("线程号%lu:开始执行函数。argv=%d\n",pthread_self(),*p);
sleep(1);
printf("线程号%lu:函数执行完毕!argv=%d\n",pthread_self(),*p);
return NULL;
}
int main()
{
THP *thp=createThreadPool(3);
int i=0;
for(;i<20;++i)
{
addTask(testFun,(void*)(&i));
sleep(1);
}
while(thp->curTaskNum!=0);
printf("任务执行完毕\n");
destroyThreadPool();
return 0;
}
程序运行截图: