线程池 C语言

一个简单的线程池,添加任务,做完后销毁线程池

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdbool.h>

#define PTHREAD_MAX		20	//最多有20个线程
#define TASK_FULL_NUM	100	//最多等待100个任务

//任务链表结构体
struct task{
	void *(*task_func)(int arg);//任务函数
	int task_arg;//任务函数的参数
	struct task *next;
};

//线程池
struct pthread_pool{
	pthread_t tid[PTHREAD_MAX];//线程号数组
	
	struct task *head;//任务链表的头节点
	
	unsigned int active_pthread_num;//正在运行的线程个数
	unsigned int wait_task_num;//正在等待的任务个数
	
	pthread_mutex_t m;//线程池互斥锁
	pthread_cond_t v;//线程池条件变量
	
	bool shutdown;//线程销毁标志位 flase:不销毁   true:销毁
};


void *time_sec()//计时线程
{
	static int time=0;
	while(1)
	{
		printf(" sec:%d\n",time++);
		sleep(1);
	}
}

void *f(int arg)//任务函数
{
	printf("%#x running\n",(unsigned int)pthread_self());
	while(arg)
	{
		arg--;
		sleep(1);
	}
	printf("%#x end\n",(unsigned int)pthread_self());
}


//死锁清理函数
void cleanup(void *arg)
{
	printf("%#x cleanup \n",(unsigned int)pthread_self());
	struct pthread_pool *pool = (struct pthread_pool *)arg;
	pthread_mutex_unlock(&pool->m);
}

void *func(void *arg)//线程执行的函数
{
	struct pthread_pool *pool = (struct pthread_pool *)arg;
	struct task *p =NULL;
	while(1)
	{
		//=======注册死锁退出函数====
		pthread_cleanup_push(cleanup,(void *)pool); 
		
		//=======加上互斥锁========
		pthread_mutex_lock(&pool->m);
		
		//由于没有正在等待的任务,释放互斥锁,开始等待条件变量
		if(pool->wait_task_num == 0 && pool->shutdown == false)
			pthread_cond_wait(&pool->v,&pool->m);
		
		//唤醒条件变量可能是任务链表增加,也可能是因为销毁了线程
		//如果是销毁线程引起的,那么就结束线程
		if(pool->shutdown == true)
		{
			pthread_exit(NULL);//调用死锁注册函数
		}
		
		//从任务链表中拿取任务执行,因为任务链表不为NULL,那么至少有一个任务
		p = pool->head->next;
		pool->head->next = p->next;
		
		//======释放互斥锁========
		pthread_mutex_unlock(&pool->m);
		
		//======解除死锁注册函数===
		pthread_cleanup_pop(0);  
		
		//*******在处理任务过程中禁止响应线程取消*******
		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
		
		//将正在等待的任务个数-1
		pool->wait_task_num--;
		
		//执行任务函数
		p->task_func(p->task_arg);
		
		//释放任务节点
		free(p);
		
		//*******在释放掉所有资源以后,可以取消线程*******
		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
	}
	
	pthread_exit(NULL);
}

//初始化线程池
struct pthread_pool* pthread_pool_init()
{
	struct pthread_pool *pool = malloc(sizeof(struct pthread_pool));
	if(pool == NULL)
	{
		perror("pool malloc failed");
		exit(-1);
	}
	
	//任务链表头节点的初始化---整个链表为NULL
	pool->head = malloc(sizeof(struct task));
	if(pool->head == NULL)
	{
		perror("pool->head malloc failed");
		exit(-1);
	}
	pool->head->next = NULL;
	
	//初始化完以后,一个正在运行线程都没有
	pool->active_pthread_num = 0;
	
	//初始化完以后,一个任务都没有
	pool->wait_task_num = 0;
	
	//初始化互斥锁
	pthread_mutex_init(&pool->m,NULL);
	
	//初始化条件变量
	pthread_cond_init(&pool->v,NULL);
	
	//将线程池销毁标志位置为flase---不销毁
	pool->shutdown = false;
	
	return pool;
}

//创建线程-->向线程池添加线程 
int pthread_pool_add(struct pthread_pool *pool,int addnum)
{
	//添加0个线程
	if(addnum == 0)
		return 0;//只是结束当前线程
	int i=0;
	int added=0;
	
	for(i = pool->active_pthread_num; 
			i<PTHREAD_MAX && i< pool->active_pthread_num + addnum; 
			i++)
	{
		//创建线程
		if( pthread_create( &pool->tid[i],NULL, func,(void *)pool) != 0)
		{
			perror("pthread_create faield");
			
			break;
		}
		//成功添加的线程个数
		added++;
	}
	
	//更新正在运行的线程个数
	pool->active_pthread_num += added;
	
	
	return added;
}

//任务添加函数
int pool_add_task(struct pthread_pool *pool,void *(*f)(int arg),int arg )
{
	//任务链表中已经等待的任务个数已经达到最大
	if(pool->wait_task_num == TASK_FULL_NUM)
	{
		printf("task list full\n");
		return -1;
	}
	
	//创建任务节点
	struct task *node = malloc(sizeof(struct task));
	if(node == NULL)
	{
		perror("task node malloc failed");
		exit(-1);
	}

	//将需要添加到任务链表中的函数和参数进行赋值
	node->task_func = f;
	node->task_arg = arg;
	node->next = NULL;
	
	//==========加互斥锁============
	pthread_mutex_lock(&pool->m);
	
	//把新任务加入到链表的末尾
	struct task *p = pool->head;
	while(p->next != NULL)
		p=p->next;
	p->next = node;
	
	//==========释放互斥锁==========
	pthread_mutex_unlock(&pool->m);
	
	//每当有任务加入到链表中,让正在等待的任务链表个数数值++
	pool->wait_task_num++;
	
	//向一个线程发送信号,让它开始执行
	pthread_cond_signal(&pool->v);
	
	return 0;
}

//销毁线程池
int pool_delete(struct pthread_pool *pool)
{
	//将线程池销毁标志位置为true---销毁
	pool->shutdown = true;
	
	//向所有线程发起唤醒条件变量
	pthread_cond_broadcast(&pool->v);
	
	//如果需要立即销毁所有线程,那么向所有线程发起取消信号
	//并且等待线程结束
	//---->强制取消线程可能会引起死锁q
	//---->万一任务执行函数有malloc或者其他申请资源,需要让他自己释放
	int i;
	for(i=0; i<pool->active_pthread_num; i++ )
	{
		pthread_cancel(pool->tid[i]);
		printf("tid[%d]=%#x\n",i,(unsigned int)pool->tid[i]);
		pthread_join(pool->tid[i],NULL);
	}
	
	//销毁任务链表
	struct task *p = pool->head->next;
	while(p != NULL)
	{
		pool->head->next = p->next;
		free(p);
		p = pool->head->next;
	}
	free(pool->head);
	
	//销毁线程池
	free(pool);
	
	printf("pthrad_pool end\n");
}


int main()
{
	//开启计时线程
	pthread_t tid;
	pthread_create(&tid,NULL,time_sec,NULL);
	
	struct pthread_pool *pool = pthread_pool_init();
	
	//线程池添加2个线程
	pthread_pool_add(pool,2);
	
	sleep(2);
	
	//添加任务
	pool_add_task(pool,f,3);
	pool_add_task(pool,f,6);
	
	sleep(1);
	
	//线程池添加2个线程
	pthread_pool_add(pool,1);
	
	sleep(4);
	
	pool_add_task(pool,f,5);
	pool_add_task(pool,f,3);
	
	sleep(3);
	//销毁线程池
	pool_delete(pool);
	
	//暂停
	pause();
	
	return 0;
}







发布了23 篇原创文章 · 获赞 16 · 访问量 2936

猜你喜欢

转载自blog.csdn.net/qq_41861442/article/details/102639320
今日推荐