Linux线程池的创建(超详细解析)

线程池:

若干个线程组合在一起形成线程池;

为什么需要线程池:

多线程版本服务器一个客户端就需要创建一个线程,如果客户端太多,明显不太合适;

创建思路:我们需要一个线程池结构体,然后这个结构体里面包含任务池,这个线程池结构体是全局变量,需要使用互斥锁,当子线程执行回调函数时,把该线程池作为参数传入,然后子线程可以从线程池结构体里面的任务池取出主线程创建的任务。我们也要使用条件变量,当任务池为空时,子线程阻塞等待,当任务池满时,主线程阻塞等待。

这是我们创建的线程池结构体:

typedef struct _poolTask
{
	int tasknum;//该任务的任务编号
	void *arg;//任务回调函数的参数
	void (*task_func)(void *arg);//任务回调函数
}PoolTask;
typedef struct _ThreadPool
{
	int max_job_num;//最大任务量
	int job_num;//实际任务量
	PoolTask *tasks;//任务池(任务数组)
	int job_push;//任务进入任务池的位置
	int job_pop;//任务出任务池的位置

	int thr_num;//子线程的数量
	pthread_t *threads;//线程池(子线程数组)
	int shutdown;//(是否销毁线程池)
	pthread_mutex_t pool_lock;//互斥锁
	pthread_cond_t empty_task;//条件变量
	pthread_cond_t not_empty_task;
}ThreadPool;

我们可以先创建一个threadpool.h头文件:

#ifndef _THREADPOO_H
#define _THREADPOO_H
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<pthread.h>
typedef struct _poolTask
{
	int tasknum;
	void *arg;
	void (*task_func)(void *arg);
}PoolTask;
typedef struct _ThreadPool
{
	int max_job_num;
	int job_num;
	PoolTask *tasks;
	int job_push;
	int job_pop;

	int thr_num;
	pthread_t *threads;
	int shutdown;
	pthread_mutex_t pool_lock;
	pthread_cond_t empty_task;
	pthread_cond_t not_empty_task;
}ThreadPool;

void create_threadpool(int thrnum,int maxtasknum);
void destroy_threadpool(ThreadPool *pool);
void addtask(ThreadPool *pool);
void taskRun(void *arg);

#endif

这四个函数我们要在threadpool.c中实现

void create_threadpool(int thrnum,int maxtasknum);//创建线程池
void destroy_threadpool(ThreadPool *pool);//销毁线程池
void addtask(ThreadPool *pool);//往线程池中的任务池中添加任务
void taskRun(void *arg);//任务回调函数

 我们现在pthread_pool.c定义全局变量:

ThreadPool *thrPool=NULL;
int beginnum=1000;

void create_threadpool(int thrnum,int maxtasknum);//创建线程池的实现:

void create_threadpool(int thrnum,int maxtasknum)
{
	printf("begin create\n");
	thrPool =(ThreadPool*)malloc(sizeof(ThreadPool));//向堆区申请一个ThreadPool大小的内存空间

	thrPool->thr_num=thrnum;//线程数量
	thrPool->max_job_num=maxtasknum;//最大任务量
	thrPool->shutdown=0;//为1是销毁线程池
	thrPool->job_push=0;//入队位置初始为0
	thrPool->job_pop=0;//出队位置初始为0
	thrPool->job_num=0;//实际任务量为0

	thrPool->tasks=(PoolTask*)malloc(sizeof(PoolTask)*maxtasknum);//申请任务池(任务数组)的空间

	pthread_mutex_init(&thrPool->pool_lock,NULL);//初始化互斥锁,条件变量
	pthread_cond_init(&thrPool->empty_task,NULL);
	pthread_cond_init(&thrPool->not_empty_task,NULL);

	int i=0;
	thrPool->threads=(pthread_t*)malloc(sizeof(pthread_t)*thrnum);//申请thrum个线程的空间

	pthread_attr_t attr;
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);//设置子线程为分离属性
	for(i=0;i<thrnum;i++)
	{
		pthread_create(&thrPool->threads[i],&attr,thrRun,(void*)thrPool);//循环创建子线程,子线程执行thrRun回调函数
	}
	printf("end create\n");
}

void addtask(ThreadPool *pool);//往线程池中的任务池中添加任务的实现:

void addtask(ThreadPool *pool)
{
	pthread_mutex_lock(&pool->pool_lock);//加锁
	while(pool->max_job_num<=pool->job_num)//任务池满了
	{
		pthread_cond_wait(&pool->empty_task,&pool->pool_lock);//阻塞等待并解锁
	}

	int taskpos=(pool->job_push++)%pool->max_job_num;//任务进入任务池的位置,循环进入
	pool->tasks[taskpos].tasknum=beginnum++;//任务编号加一
	pool->tasks[taskpos].arg=(void *)&pool->tasks[taskpos];//把自己的地址传给任务自己的参数
	pool->tasks[taskpos].task_func=taskRun;//任务回调函数
	pool->job_num++;//实际任务数加一

	pthread_mutex_unlock(&pool->pool_lock);//解锁
	pthread_cond_signal(&pool->not_empty_task);//通知子线程阻塞的条件变量
}

void destroy_threadpool(ThreadPool *pool);//销毁线程池的实现:

void destroy_threadpool(ThreadPool *pool)
{
	pool->shutdown=1;//改为一,表示摧毁线程池
	pthread_cond_broadcast(&pool->not_empty_task);//通知子线程的条件变量不再阻塞

	pthread_cond_destroy(&pool->not_empty_task);//销毁锁,条件变量
	pthread_cond_destroy(&pool->empty_task);
	pthread_mutex_destroy(&pool->pool_lock);

	free(pool->tasks);//释放
	free(pool->threads);
	free(pool);
}

子线程回调函数thrRun的实现:

void *thrRun(void *arg)
{
	ThreadPool *pool=(ThreadPool*)arg;//强转参数的类型
	int taskpos=0;
	PoolTask *task=(PoolTask*)malloc(sizeof(PoolTask));//申请一个任务的空间
	while(1)//一直死循环,子线程不退化出
	{
		pthread_mutex_lock(&thrPool->pool_lock);//加锁

		while(thrPool->job_num<=0&&!thrPool->shutdown)//用while循环是三个子线程都阻塞,获得信号时只有一个线程获得锁,其他线程尝试加锁,又会阻塞,当获得锁的线程执行完任务后,其他线程继续while循环。
		{
			pthread_cond_wait(&thrPool->not_empty_task,&thrPool->pool_lock);
		}
		if(thrPool->job_num)//实际任务数量
		{
			taskpos=(thrPool->job_pop++)%thrPool->max_job_num;//任务出任务池的位置
			memcpy(task,&thrPool->tasks[taskpos],sizeof(PoolTask));//把任务池的任务的复制一份出来,防止主线程同时对该任务的值改变
			task=task->arg;//改变为之前任务池任务的地址
			thrPool->job_num--;//实际任务数量-1
			pthread_cond_signal(&thrPool->empty_task);//向主线程发送信号
		}
		if(thrPool->shutdown)//销毁线程池
		{
			pthread_mutex_unlock(&thrPool->pool_lock);//解锁
			free(task);//释放task的内存
			pthread_exit(NULL);//退出
		}
		pthread_mutex_unlock(&thrPool->pool_lock);//正常解锁
		task->task_func(task->arg);//执行任务回调函数
	}
}

void taskRun(void *arg);//任务回调函数的实现

 

void taskRun(void *arg)
{
	PoolTask*task=(PoolTask*)arg;
	printf("task:numer==[%d]\n",task->tasknum);//打印任务的编号
}

完整的pthreadpool.c

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<pthread.h>
#include"threadpool.h"
ThreadPool *thrPool=NULL;
int beginnum=1000;
void taskRun(void *arg)
{
	PoolTask*task=(PoolTask*)arg;
	printf("task:numer==[%d]\n",task->tasknum);
}
void *thrRun(void *arg)
{
	ThreadPool *pool=(ThreadPool*)arg;
	int taskpos=0;
	PoolTask *task=(PoolTask*)malloc(sizeof(PoolTask));
	while(1)
	{
		pthread_mutex_lock(&thrPool->pool_lock);

		while(thrPool->job_num<=0&&!thrPool->shutdown)
		{
			pthread_cond_wait(&thrPool->not_empty_task,&thrPool->pool_lock);
		}
		if(thrPool->job_num)
		{
			taskpos=(thrPool->job_pop++)%thrPool->max_job_num;
			memcpy(task,&thrPool->tasks[taskpos],sizeof(PoolTask));
			task=task->arg;
			thrPool->job_num--;
			pthread_cond_signal(&thrPool->empty_task);
		}
		if(thrPool->shutdown)
		{
			pthread_mutex_unlock(&thrPool->pool_lock);
			free(task);
			pthread_exit(NULL);
		}
		pthread_mutex_unlock(&thrPool->pool_lock);
		task->task_func(task->arg);
	}
}
void create_threadpool(int thrnum,int maxtasknum)
{
	printf("begin create\n");
	thrPool =(ThreadPool*)malloc(sizeof(ThreadPool));

	thrPool->thr_num=thrnum;
	thrPool->max_job_num=maxtasknum;
	thrPool->shutdown=0;
	thrPool->job_push=0;
	thrPool->job_pop=0;
	thrPool->job_num=0;

	thrPool->tasks=(PoolTask*)malloc(sizeof(PoolTask)*maxtasknum);

	pthread_mutex_init(&thrPool->pool_lock,NULL);
	pthread_cond_init(&thrPool->empty_task,NULL);
	pthread_cond_init(&thrPool->not_empty_task,NULL);

	int i=0;
	thrPool->threads=(pthread_t*)malloc(sizeof(pthread_t)*thrnum);

	pthread_attr_t attr;
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
	for(i=0;i<thrnum;i++)
	{
		pthread_create(&thrPool->threads[i],&attr,thrRun,(void*)thrPool);
	}
	printf("end create\n");
}
void addtask(ThreadPool *pool)
{
	pthread_mutex_lock(&pool->pool_lock);
	while(pool->max_job_num<=pool->job_num)
	{
		pthread_cond_wait(&pool->empty_task,&pool->pool_lock);
	}

	int taskpos=(pool->job_push++)%pool->max_job_num;
	pool->tasks[taskpos].tasknum=beginnum++;
	pool->tasks[taskpos].arg=(void *)&pool->tasks[taskpos];
	pool->tasks[taskpos].task_func=taskRun;
	pool->job_num++;

	pthread_mutex_unlock(&pool->pool_lock);
	pthread_cond_signal(&pool->not_empty_task);
}
void destroy_threadpool(ThreadPool *pool)
{
	pool->shutdown=1;
	pthread_cond_broadcast(&pool->not_empty_task);

	pthread_cond_destroy(&pool->not_empty_task);
	pthread_cond_destroy(&pool->empty_task);
	pthread_mutex_destroy(&pool->pool_lock);

	free(pool->tasks);
	free(pool->threads);
	free(pool);
}
int main()
{
	create_threadpool(3,20);//创建3个子线程,最大任务量为20
	int i=0;
	for(i=0;i<50;i++)//循环添加50个任务
	{
		addtask(thrPool);
	}
	sleep(20);
	destroy_threadpool(thrPool);//销毁线程池
	return 0;
}

结果:

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落落落sss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值