实现一个简单的线程池
我们知道同一进程中的多条线程将共享该进程中的全部系统资源,频繁的创建和结束线程会占用大量的系统资源,而线程池可以避免这种情况。
简单的来说,线程池就是多个线程的集合。这些线程在执行完当前任务后不会立即结束,而是执行下一个任务。若没有任务可执行,它们就会阻塞并等待下一个任务。线程池只在销毁时会结束所有线程。这样以来就避免了频繁创建和结束线程的情况,下面讲讲如何实现一个简单的线程池。
作者的线程池主要是由多个常驻线程和任务队列组成的。任务队列由链表来实现,里面的每个任务中都有相应的处理函数和内容。常驻线程在无任务时阻塞,有任务时唤醒并从任务队列中读取任务并执行。最后线程池在销毁时结束所有线程。
需要注意的时每次读取和写入任务时注意对数据的保护
下面贴出代码
#include<stdio.h>
#include <errno.h>
#include<pthread.h>
#include<stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
void my_error(const char *error_string, int line);
void add_func(void *(*func)(void *arg),void *arg);
void *mainfun(void *arg);
void init_threadpool(int max);
void destroypool();
void *simplework(void *arg);
void my_error(const char *error_string, int line) //错误处理函数
{
fprintf(stderr, "line:%d",line);
perror(error_string);
exit(1);
}
struct work_list{
//定义任务队列,链表实现
void *(*func)(void *arg);//处理函数
void *arg;//处理函数的参数
struct work_list *next;//指向下一个任务的指针
};
struct pthread_pool{
//定义线程池
pthread_mutex_t mutex;
pthread_cond_t cond;
int max_threads;
int work_num;//剩余任务数
int isdestroy;//是否销毁线程池
pthread_t* thread;
struct work_list *list_head;//指向任务队列的头结点
};
struct pthread_pool* pool;
void add_func(void *(*func)(void *arg),void *arg) //向任务队列中添加任务
{
struct work_list *a;
a=(struct work_list *)malloc(sizeof(struct work_list));
a->next=NULL;
a->func=func;
a->arg=arg; //使用尾插法将任务插入任务队列
if (pool->list_head==NULL)
{
pool->list_head=a;
}
else {
struct work_list *p;
p=pool->list_head;
while(p->next!=NULL)
{
p=p->next;
}
p->next=a;
}
pool->work_num++;
pthread_mutex_unlock(&(pool->mutex));
pthread_cond_signal(&(pool->cond)); //唤醒等待的线程
}
void *mainfun(void *arg) //线程
{
while(1)
{
pthread_mutex_lock(&(pool->mutex));
while(pool->list_head==NULL&&pool->work_num==0) //若无任务则进入循环,有任务就会先执行任务
{
if (pool->isdestroy==1)//若需要销毁线程池
{
pthread_mutex_unlock(&(pool->mutex));//注意退出时当前线程一定要先解锁,不然其他线程会阻塞无法退出
printf("pthread %d has destroyed\n",pthread_self());
pthread_exit(NULL);
}
else {
printf("%d is waiting\n",pthread_self());
pthread_cond_wait(&(pool->cond),&(pool->mutex));
printf("%d is awake\n",pthread_self());
}
}
struct work_list *work=pool->list_head;
pool->list_head=pool->list_head->next;
pool->work_num--;
pthread_mutex_unlock(&(pool->mutex));
(*(work->func)) (work->arg);
free(work);
work=NULL;
}
pthread_exit(NULL);
}
void init_threadpool(int max)//初始化线程池
{
pool=(struct pthread_pool *)malloc(sizeof(struct pthread_pool));
if (pool == NULL)
{
my_error("malloc",__LINE__);
}
pool->max_threads=max;
pool->work_num=0;
pool->isdestroy=0;
pool->list_head=NULL;
pthread_mutex_init(&(pool->mutex),NULL);
pthread_cond_init(&(pool->cond),NULL);
int i=0;
pool->thread=(pthread_t*)malloc(max*sizeof(pthread_t));
if (pool->thread == NULL)
{
my_error("malloc",__LINE__);
}
int ret;
for (i=0;i<max;i++)
{
ret=pthread_create(&(pool->thread[i]),NULL,mainfun,NULL);
if (ret!=0)
{
my_error("pthread_create",__LINE__);
}
}
printf("init is sucess\n");
}
void destroypool()
{
pthread_mutex_lock(&(pool->mutex));
pool->isdestroy=1;
pthread_mutex_unlock(&(pool->mutex));
pthread_cond_broadcast(&(pool->cond));
printf("i call everyone\n");
int i=0;
for (i=0;i<pool->max_threads;i++)
{
pthread_join(pool->thread[i],NULL);
}
free(pool->thread);
pthread_cond_destroy(&(pool->cond));
pthread_mutex_destroy(&(pool->mutex));
free(pool);
}
void *simplework(void *arg)
{
printf("%d is working %d\n",pthread_self(),*(int*)arg);
sleep(1);
}
int main()
{
init_threadpool(10);
int i=0;
for (i=0;i<5;i++)
{
pthread_mutex_lock(&(pool->mutex));
add_func(simplework,&i);
}
sleep(5);
destroypool();
printf("destory compelete\n");
return 0;
}