linux 线程池设计

线程池是某个iot项目中用到的核心组件之一,基于reactor模型设计,运行在树莓派上面,是用c语言语言写的。 这个源码曾经抠出来,放在一个flamingo的群里面,群里面有人用来做电信机房的组件。 一忙起来,就忘记把这个源码写成博客,为更多的人提供技术交流。

在这里插入图片描述

源码:

//thread_pool.h
#ifndef THREAD_POOL_H_
#define THREAD_POOL_H_

#define THREAD_NUM_CPU      -1

struct thread_pool;
struct thread_task;

typedef struct thread_task thread_task_t;

typedef void * (*task_func)(void *);

/**
 * 创建一个线程池
 * @thread_num: 线程池内线程的数目,传入THREAD_NUM_CPU则默认为
 *      处理器核心数量
 */
struct thread_pool * thread_pool_create(int thread_num);

/**
 * 将一个创建好的任务放入线程池队列中
 * @pool:线程池
 * @task:事先创建的任务
 */
int thread_pool_queue_task(struct thread_pool * pool, thread_task_t * task);

/**
 * 使用func(arg)创建任务并放入队列中,由线程池分配和释放任务结构
 * 任务完成后不能获取任务的返回值
 * @pool:线程池
 * @func:要执行的函数
 * @arg:传给函数的参数
 */
int thread_pool_new_task(struct thread_pool * pool, task_func func, void * arg, unsigned long long repeat_id);

/**
 * 等待所有线程池中的任务完成,包括已经在执行的和在队列中的
 * @pool:线程池
 */
void thread_pool_wait_all(struct thread_pool * pool);

/**
 * 释放一个线程池占用的资源,调用这个函数会阻塞直到所有线程池创建的线程退出
 * 并且会回收所有在队列中的thread_task_t结构,任何其他的对任务结构的指针
 * 都会成为悬空指针。
 * 这个函数会有内存泄露问题,因为已经在执行中的thread_task_t可能没有被释放
 * 一般情况下不应该调用这个函数,还是让程序结束时操作系统来回收资源。
 * @pool:线程池
 */
void thread_pool_destory(struct thread_pool * pool);

/**
 * 创建一个线程池任务,返回的thread_task_t可以用于等待该任务完成后获取任务
 * 的返回值。
 * @func:要执行的函数
 * @arg:传给函数的参数
 */
thread_task_t * thread_task_create(task_func func, void * arg, unsigned long long repeat_id);

/**
 * 创建一个线程池动态任务,返回的thread_task_t可以用于等待该任务完成后获取任务
 * 的返回值。
 * @func:要执行的函数
 * @arg:传给函数的参数
 * note: 任务对象在执行完毕后,自动被线程池销毁
 */
thread_task_t * thread_dynamic_task_create(task_func func, void * arg, unsigned long long repeat_id);

/**
 * 释放任务结构占用的资源。
 * @task:要释放的任务
 * @free_result:不为0则释放任务完成后返回的结果指针
 */
void thread_task_destroy(thread_task_t * task, int free_result);

/**
 * 等待一个放入线程池队列的任务执行完毕,成功返回0,若task没有进入队列返回-1
 * @task:要等待的任务
 */
int thread_task_wait(thread_task_t * task);

/**
 * 监测任务是否执行完毕。返回0,执行完毕。返回-2,正在线程池中(等待被)执行。
 * 返回-1,任务没有注入到线程池
 */
int thread_task_nowait(thread_task_t * task);


/**
 * 任务执行完毕后获得函数的返回值,调用此函数前应调用thread_task_wait等待
 * 任务执行完毕,否则结果NULL。
 * @task:要获取结果的任务
 */
void * thread_task_get_result(thread_task_t * task);

#endif /* THREAD_POOL_H_ */

//thread_pool.c
#include "thread_pool.h"
#include "tp_atomic.h"

#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <assert.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/eventfd.h>
#include <sys/epoll.h>

#define OK_VALUE				0x80000000


enum {
	THREAD_POOL_ERROR,
	THREAD_POOL_INIT_FAIL,
	THREAD_POOL_CREATE_THREAD_FAIL,
};


enum {
	THREAD_TYPE_INPOOL, 			/* 线程池常驻线程 */
	THREAD_TYPE_TEMP,			/* 临时线程 */
};


enum {
	THREAD_STATUS_IDLE,
	THREAD_STATUS_RUNNING,
};


enum {
	THREAD_TASK_NORMAL, 			/* 通过thread_task_create()创建的任务 */
	THREAD_TASK_NO_RESULT,			/* 通过thread_pool_new_task()创建的任务 */
};


enum {
	THREAD_TASK_STATUS_READY, 		/* 业务对象创建完成,尚未注入线程池 */
	THREAD_TASK_STATUS_INQUEUE, 		/* 业务注入线程池就绪队列 */
	THREAD_TASK_STATUS_RUNNING, 		/* 业务被线程池某个线程执行 */
	THREAD_TASK_STATUS_DONE, 		/* 业务被线程执行完毕 */
};


struct thread_pool_event {
	pthread_mutex_t mutex;
	pthread_cond_t	cond;
};


typedef struct thread_pool_event thread_pool_event_t;


static int thread_pool_event_init(thread_pool_event_t * event)
{
	if (pthread_mutex_init(&event->mutex, NULL) != 0)
		return - 1;

	if (pthread_cond_init(&event->cond, NULL) != 0) {
		pthread_mutex_destroy(&event->mutex);
		return - 1;
	}

	return 0;
}


static void thread_pool_event_destory(thread_pool_event_t * event)
{
	pthread_mutex_destroy(&event->mutex);
	pthread_cond_destroy(&event->cond);
}


static int thread_pool_event_lock(thread_pool_event_t * event)
{
	return pthread_mutex_lock(&event->mutex);
}


static int thread_pool_event_unlock(thread_pool_event_t * event)
{
	return pthread_mutex_unlock(&event->mutex);
}


static int thread_pool_event_wait(thread_pool_event_t * event)
{
	return pthread_cond_wait(&event->cond, &event->mutex);
}


static int thread_pool_event_trywait(thread_pool_event_t * event, int timeout)
{
	struct timespec abstime;

	abstime.tv_sec		= time(NULL) +timeout;
	abstime.tv_nsec 	= 0;

	return pthread_cond_timedwait(&event->cond, &event->mutex, &abstime);
}

static int thread_pool_event_notify(thread_pool_event_t * event)
{
	return pthread_cond_signal(&event->cond);
}


struct thread_task {
	unsigned long long	repeat_id;			/* 0,任务可以在多个线程同时执行;
									!=0,repeat_id值相同的任务同一时刻最多占用一个执行线程 */
	int 			task_id;
	task_func		func;
	void *			arg;
	int 			task_type;
	int 			task_status;
	void *			result;
	struct thread_task * next;
	thread_pool_event_t event;
};


struct thread_pool {
	int 			th_num; 			/* 常驻线程数量,池总线程容量 */
	int 			th_real_num;			/* 实际线程总数 */
	int 			pool_status;
	struct thread_struct * threads; 			/* 线程数据结构数组,成员数为th_num个 */
	thread_task_t * task_queue; 				/* 任务队列 */
	atomic_t		task_total; 			/* 收到的任务总数 */
	atomic_t		task_running;			/* 运行中的任务数量 */
	atomic_t		task_queued;			/* 队列中的任务数量 */
	atomic_t		task_done;			/* 完成的任务总数 */
	atomic_t		task_error; 			/* 出错的任务数量 */
	pthread_t		manager;			/* 管理线程 */
	thread_pool_event_t event_queue;			/* 通知管理线程有任务到来的事件 */
	thread_pool_event_t event_alldone;			/* 所有任务完成时的事件通知 */
	struct epoll_event * events_epoll;			/* 指向th_num个struct epoll_event */
	unsigned long long * repeat_ids;			/* 指向th_num个线程的 repeat_id */
};


struct thread_struct {
	pthread_t		thread_id;
	struct thread_pool * 	pool;
	unsigned long long *	p_repeat_id;			/* 线程执行线程 pool->repeat_ids[i]*/
	int 			thread_type;
	int 			thread_status;
	int 			eventfds[2];	/*
						线程池管理线程 与 线程池执行线程s的通讯数组
						eventfds[0]存放待执行任务对象的地址
						eventfds[1]存放 task_queue[]中需要注入该线程的成员的指针
						*/
};


/**
 *函数功能:		线程池业务创建(封装)
 *参数:		func 任务执行函数指针
 		arg 任务参数
 *返回值:		下创建的任务对象的指针
 */
static thread_task_t * _thread_task_create(task_func func, void * arg, unsigned long long repeat_id, int type)
{
	thread_task_t * task;

	if ((task = malloc(sizeof(thread_task_t))) == NULL)
		return NULL;

	if (type == THREAD_TASK_NORMAL) {
		if (thread_pool_event_init(&task->event) != 0) {
			free(task);
			return NULL;
		}
	}

	task->repeat_id		= repeat_id;
	task->func		= func;
	task->arg		= arg;
	task->task_type 	= type;
	task->task_status	= THREAD_TASK_STATUS_READY;
	task->result		= NULL;
	task->next		= NULL;

	return task;
}


/**
 *函数功能:		封装一个线程池业务
 *参数:		func 待执行的业务函数
 		arg 传递给业务函数的参数
 		repeat_id	为0则任务可在多个线程同时执行。>0则相同repeat_id的任务同一时刻只能在一个线程执行
 */
thread_task_t * thread_task_create(task_func func, void * arg, unsigned long long repeat_id)
{
	return _thread_task_create(func, arg, repeat_id, THREAD_TASK_NORMAL);
}

/**
 *函数功能:		封装一个线程池业务
 *参数:		func 待执行的业务函数
 		arg 传递给业务函数的参数
 		repeat_id	为0则任务可在多个线程同时执行。>0则相同repeat_id的任务同一时刻只能在一个线程执行
 */
thread_task_t * thread_dynamic_task_create(task_func func, void * arg, unsigned long long repeat_id)
{
	return _thread_task_create(func, arg, repeat_id, THREAD_TASK_NO_RESULT);
}


/**
 *函数功能:		阻塞等待指定的任务执行完成。
 *返回值:		-1 此任务不在任务队列中
 		0 此任务被某线程执行完毕
 */
int thread_task_wait(thread_task_t * task)
{
	/* 没有放入线程池队列? */
	if (task->task_status == THREAD_TASK_STATUS_READY)
		return - 1;

	thread_pool_event_lock(&task->event);

	while (task->task_status != THREAD_TASK_STATUS_DONE)
		thread_pool_event_wait(&task->event);

	thread_pool_event_unlock(&task->event);

	return 0;
}

/**
 *函数功能:		非阻塞读取业务是否执行完成
 *参数:		业务对象指针
 */
int thread_task_nowait(thread_task_t * task)
{
	int		ret;

	/* 没有放入线程池队列? */
	if (task->task_status == THREAD_TASK_STATUS_READY)
		return - 1;

	thread_pool_event_lock(&task->event);

	if (task->task_status != THREAD_TASK_STATUS_DONE) {
		ret = -2;
	}
	else {
		ret = 0;
	}

	thread_pool_event_unlock(&task->event);

	return ret;
}


/**
 *函数功能:		通知执行线程正在执行的任务,任务执行成功,设置任务状态为done
 */
static int thread_task_notify(thread_task_t * task)
{
	thread_pool_event_lock(&task->event);
	task->task_status	= THREAD_TASK_STATUS_DONE;
	thread_pool_event_notify(&task->event);
	thread_pool_event_unlock(&task->event);

	return 0;
}


/**
 *函数功能:		销毁任务对象
 */
void thread_task_destroy(thread_task_t * task, int free_result)
{
	if (task->task_type == THREAD_TASK_NORMAL)
		thread_pool_event_destory(&task->event);

	if (free_result)
		free(task->result);

	free(task);
}


/**
 *函数功能:		获取任务执行结果首地址
 */
void * thread_task_get_result(thread_task_t * task)
{
	return task->result;
}


/**
 *函数功能:		线程池所有线程执行任务完毕,发生信号通知给线程池alldone事件
 */
static void thread_pool_signal_alldone(struct thread_pool * pool)
{
	thread_pool_event_lock(&pool->event_alldone);
	thread_pool_event_notify(&pool->event_alldone);
	thread_pool_event_unlock(&pool->event_alldone);
}


/**
 *函数功能:		执行线程(外壳)
 */
static void * thread_pool_handler(void * vthread)
{
	struct thread_struct * thread = vthread;
	thread_task_t * task = NULL;

	struct thread_pool * pool = thread->pool;
	uint64_t		ok	= OK_VALUE, task_addr = 0;

	while (1) {
		/* 阻塞读取待执行任务对象的指针,线程池管理线程会把任务指针写入thread->eventfds[1]中 */
		if (read(thread->eventfds[1], &task_addr, sizeof(uint64_t)) != sizeof(uint64_t)) {
			atomic_inc(&pool->task_error);
			continue;
		}

		task				= (thread_task_t *)task_addr;
		thread->thread_status = THREAD_STATUS_RUNNING;
		task->task_status	= THREAD_TASK_STATUS_RUNNING;
		atomic_inc(&pool->task_running);
		task->result		= task->func(task->arg);	/* 执行任务 */

		//printf("-----------------线程执行完毕,原始id=[%llu]-------------------\r\n", *thread->p_repeat_id);
		//printf("-----id地址为:%p\r\n", thread->p_repeat_id);
		*thread->p_repeat_id = 0;
		//printf("---------修改后id=[%llu]\r\n", *thread->p_repeat_id);

		atomic_dec(&pool->task_running);
		atomic_inc(&pool->task_done);
		thread->thread_status = THREAD_STATUS_IDLE;

		if (task->task_type == THREAD_TASK_NO_RESULT)
			thread_task_destroy(task, 0);
		else if (task->task_type == THREAD_TASK_NORMAL)
			thread_task_notify(task);

		if (atomic_read(&pool->task_done) == atomic_read(&pool->task_total))
			thread_pool_signal_alldone(pool);

		/* 通知线程池管理线程,执行线程执行完毕任务 */
		if (write(thread->eventfds[0], &ok, sizeof(uint64_t)) != sizeof(uint64_t))
			atomic_inc(&pool->task_error);

	}

	return NULL;
}


/**
 *函数功能:		找到任务注入的执行线程,返回其指针
 *参数:		pool 线程池
 		fd 存放任务对象的地址
 */
static
struct thread_struct * thread_pool_get_thread_by_fd(struct thread_pool * pool, int fd) {
	for (int i = 0; i < pool->th_num; i++) {
		struct thread_struct * thread = &pool->threads[i];

		if (thread->eventfds[0] == fd)
			return thread;
	}

	return NULL;
}

/**
 *函数功能:		线程池管理线程,负责创建线程池、调度线程

备注:		可视情况,在线程创建后增加线程的栈大小 
 */
static void * thread_pool_manager(void * vpool)
{
	pthread_attr_t 		attr;
	int			stacksize = 1024 * 128; 			/* thread 堆栈设置为128K,stacksize以字节为单位*/
	struct thread_pool * 	pool = vpool;
	int 			epollfd = epoll_create(1);
	struct epoll_event 	event;


	/* 创建初始化线程属性对象、设置线程属性->栈size */
	if (0 != pthread_attr_init(&attr)) {
		printf("线程池属性初始化失败\r\n");
		sleep(2);
		exit(-1);
	}
	if (0 != pthread_attr_setstacksize(&attr, stacksize)) {
		printf("线程池属性初始化失败, 设置栈size\r\n");
		sleep(2);
		exit(-1);		
	}

	/* 创建线程池 */
	printf("pool->repeat_ids: %p\r\n", pool->repeat_ids);
	for (int i = 0; i < pool->th_num; i++) {
		struct thread_struct * thread = &pool->threads[i];
		thread->thread_type = THREAD_TYPE_INPOOL;
		thread->thread_status = THREAD_STATUS_IDLE;
		thread->pool		= pool;
		thread->p_repeat_id	= pool->repeat_ids + i;
		thread->eventfds[0] = eventfd(OK_VALUE, 0);		//管理线程epoll此事件fd,执行线程在执行完任务后写入此事件(表示此线程执行完任务)
		thread->eventfds[1] = eventfd(0, 0);
		event.events		= EPOLLIN;
		event.data.fd		= thread->eventfds[0];

		/* 线程创建fail 或 线程加入线程池失败,则销毁线程池中已经创建的所有线程 */
		int 			epoll_ctl_ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, thread->eventfds[0], &event);
		int 			pthread_create_ret = pthread_create(&thread->thread_id, &attr, thread_pool_handler, thread);

		if (epoll_ctl_ret != 0 || pthread_create_ret != 0) {
			for (int j = 0; j < i; j++)
				pthread_cancel(pool->threads[i].thread_id);

			pool->pool_status	= THREAD_POOL_CREATE_THREAD_FAIL;
			return NULL;
		}

		printf("第%d个执行线程的id地址是:%p\r\n", i,thread->p_repeat_id);
	}

	/* 不再使用线程属性,将其销毁 */
	pthread_attr_destroy(&attr); 					


	/* 调度线程:将线程池中的任务队列,注入到idle线程 */
	uint64_t		ok	= 0, task_addr = 0;

	while (1) {
		thread_task_t * taskqueue, * taskqueue_noconflict, *taskqueue_conflict;
		
		/* 阻塞等待任务 */
		thread_pool_event_lock(&pool->event_queue);

		while (pool->task_queue == NULL)
			thread_pool_event_wait(&pool->event_queue);

		/* 获取任务队列头 */
		taskqueue		= pool->task_queue;
		pool->task_queue	= NULL;
		thread_pool_event_unlock(&pool->event_queue);


		/* -----------------------------------下面任务需要阻塞等待线程池把任务队列执行完毕-------------------*/
		while (NULL != taskqueue) {

			taskqueue_noconflict = NULL;
			taskqueue_conflict = NULL;

			/* 遍历线程池,遍历任务队列。构建一条队列 */
			while (1) {
				int		m;
				thread_task_t * cur, * node, * next;
			

				if (NULL == taskqueue) {					/* 任务队列分解完毕,则退出分解 */
					taskqueue = taskqueue_conflict;
					break;
				}
				
				cur = taskqueue;
				for (m=0; m<pool->th_num; m++) {				/* 遍历线程池,判断是任务 与 线程是否冲突? */
					if (0 == cur->repeat_id) {
						//printf("非冲突业务\r\n");
						m = pool->th_num;
						break;
					}

					if (cur->repeat_id == pool->repeat_ids[m]) {
						break;
					}
				}
				
				if (m >= pool->th_num) {					/* cur任务与线程池不冲突? */
					if (NULL == taskqueue_noconflict) {				/* cur任务插入taskqueue_noconflict头 */
						next = taskqueue->next;					/* cur节点从taskqueue链表取下,插入不冲突链表 */
						taskqueue = next;

						taskqueue_noconflict = cur;
						cur->next = NULL;
					}
					else {								/* cur插入taskqueue_noconflict尾 */
						int	confilct;

						confilct = 0;
						node = taskqueue_noconflict;
						while ((NULL != node) && (0 != cur->repeat_id)) {
							if (cur->repeat_id == node->repeat_id) {
								confilct = 1;

								break;
							}

							next = node->next;
							node = next;
						}
						
						if (0 == confilct) {
							node = taskqueue_noconflict;
							while (NULL != node->next) {
								next = node->next;
								node = next;
							}
							node->next = cur;
							cur->next = NULL;
						}
						else {
							goto label1;
						}
					}
				}
				else {								/* node与线程池冲突 */
				label1:
					if(NULL == taskqueue_conflict) {				/* node节点插入taskqueue_conflict头 */
						next = taskqueue->next;					/*  */
						taskqueue = next;

						taskqueue_conflict = cur;
						cur->next = NULL;
					}
					else {								/* node节点插入taskqueue_conflict尾 */	
						node  = taskqueue_conflict;
						while(NULL != node->next) {
							next = node->next;
							node = next;
						}
						node->next = cur;
						cur->next = NULL;
					}
				}

				if (NULL == taskqueue_noconflict) {
					usleep(50);
				}
				else {
					break;
				}
			}


			/* 将非冲突任务注入执行线程 */
			while (taskqueue_noconflict != NULL) {
				
				/* 阻塞等待线程池中有线程执行完毕(变为idle) */
				int 			fdn = epoll_wait(epollfd, pool->events_epoll, pool->th_num, -1);

				/* 遍历线程池,将任务注入线程 */
				for (int i = 0, j = 0; (j < fdn) && (i < pool->th_num) && (NULL != taskqueue_noconflict); i++) {	
					struct epoll_event * e = &pool->events_epoll[i];	/* 获取线程事件 */

					/* 空闲线程? */
					if (e->events & EPOLLIN) {
						atomic_dec(&pool->task_queued);
						int 			fd	= e->data.fd;

						ssize_t ret = read(fd, &ok, sizeof(uint64_t));
						if (ret == -1) {
							perror("read thread task queue");
						}
						assert(ok == OK_VALUE);

						struct thread_struct * thread;
						thread				= thread_pool_get_thread_by_fd(pool, fd);

						printf("----------------调试装--------------------------\r\n");
						/* 这里不能直接在for里用taskqueue = taskqueue->next
						 * 因为在执行这句语句之前可能执行任务的线程就被调度并且执行完毕
						 * 将这个task结构释放掉了,这时next就会成为无效指针
						 * 所以需要一个临时变量
						 */
						//thread_task_t * tmptask;
						thread_task_t * tmptask 	= taskqueue_noconflict->next;
						task_addr			= (uint64_t)taskqueue_noconflict;

						/* 任务防冲突id写入执行线程 */
						pool->repeat_ids[i] = taskqueue_noconflict->repeat_id;

						/* 将任务注入执行线程 */
						if (write(thread->eventfds[1], &task_addr, sizeof(uint64_t)) != sizeof(uint64_t))
							atomic_inc(&pool->task_error);

						/* 任务队列头指向下一个待执行任务 */
						taskqueue_noconflict			= tmptask;

						j++;

						break;
					}
				}
			}
		}
	}

	return NULL;
}



/**
 *函数功能:		线程池管理线程,负责创建线程池、调度线程

备注:		可视情况,在线程创建后增加线程的栈大小 
 */
static void * thread_pool_manager(void * vpool)
{
	pthread_attr_t 		attr;
	int			stacksize = 1024 * 64; 			/* thread 堆栈设置为64K,stacksize以字节为单位*/
	struct thread_pool * 	pool = vpool;
	int 			epollfd = epoll_create(1);
	struct epoll_event 	event;


	/* 创建初始化线程属性对象、设置线程属性->栈size */
	if (0 != pthread_attr_init(&attr)) {
		printf("线程池属性初始化失败\r\n");
		sleep(2);
		exit(-1);
	}
	if (0 != pthread_attr_setstacksize(&attr, stacksize)) {
		printf("线程池属性初始化失败, 设置栈size\r\n");
		sleep(2);
		exit(-1);		
	}

	/* 创建线程池 */
	printf("pool->repeat_ids: %p\r\n", pool->repeat_ids);
	for (int i = 0; i < pool->th_num; i++) {
		struct thread_struct * thread = &pool->threads[i];
		thread->thread_type = THREAD_TYPE_INPOOL;
		thread->thread_status = THREAD_STATUS_IDLE;
		thread->pool		= pool;
		thread->p_repeat_id	= pool->repeat_ids + i;
		thread->eventfds[0] = eventfd(OK_VALUE, 0);		//管理线程epoll此事件fd,执行线程在执行完任务后写入此事件(表示此线程执行完任务)
		thread->eventfds[1] = eventfd(0, 0);
		event.events		= EPOLLIN;
		event.data.fd		= thread->eventfds[0];

		/* 线程创建fail 或 线程加入线程池失败,则销毁线程池中已经创建的所有线程 */
		int 			epoll_ctl_ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, thread->eventfds[0], &event);
		int 			pthread_create_ret = pthread_create(&thread->thread_id, &attr, thread_pool_handler, thread);

		if (epoll_ctl_ret != 0 || pthread_create_ret != 0) {
			for (int j = 0; j < i; j++)
				pthread_cancel(pool->threads[i].thread_id);

			pool->pool_status	= THREAD_POOL_CREATE_THREAD_FAIL;
			return NULL;
		}

		printf("第%d个执行线程的id地址是:%p\r\n", i,thread->p_repeat_id);
	}

	/* 不再使用线程属性,将其销毁 */
	pthread_attr_destroy(&attr); 					


	/* 调度线程:将线程池中的任务队列,注入到idle线程 */
	uint64_t		ok	= 0, task_addr = 0;

	while (1) {
		thread_task_t * taskqueue, * taskqueue_noconflict;
		thread_task_t * tmptask;

		/* 阻塞等待任务 */
		thread_pool_event_lock(&pool->event_queue);

		while (pool->task_queue == NULL)
			thread_pool_event_wait(&pool->event_queue);

		/* 获取任务队列头 */
		taskqueue		= pool->task_queue;
		pool->task_queue	= NULL;
		thread_pool_event_unlock(&pool->event_queue);


		taskqueue_noconflict	= taskqueue;
		/* 遍历线程池,遍历任务队列。构建一条队列 */
		while (0) {
			int		ready_flag;
			int		m;
			thread_task_t * node, * prev, * next;
		
		
			ready_flag = 0;
			prev = NULL;
			node = taskqueue;
			next = taskqueue->next;
			/* 遍历任务队列,从中取下一个与现有线程不冲突的任务 */
			for ( ; taskqueue != NULL; )
			{	
				if (NULL == node) {			/* 任务遍历全部冲突,则重新遍历整个任务队列 */
					ready_flag = 0;
					break;
				}
		
				if (0 == node->repeat_id) {
					ready_flag = 1;
					break;				/* 不需要避免线程冲突的任务,则跳过判断冲突 */
				}
				
				printf("这是一个需要防止线程冲突的任务,请谨慎处理之\r\n");
				
				/* 当前任务节点的id与所有线程的id对比 */
				for (m = 0; m < pool->th_num; m++) {
					if (node->repeat_id == pool->repeat_ids[m]) {	// conflict occured!
						if (NULL == next) {
							printf("冲突,\r\n");
							break;		/* node是最后一个节点 */
						}
						
						prev = node;
						node = next;
						if (NULL != node) {
							next = node->next;	/* 比对下一个任务节点 */
						}
						
						break;
					}
				}
		
				/* 当前任务(node)与现有线程不冲突,从任务链表取下node,跳出do() while{}循环 */
				if (m >= pool->th_num) {
		
					if (NULL == prev) {		/* 第一个节点就不冲突 */
						printf("第一个节点不冲突\r\n");
						taskqueue = taskqueue->next;
					}
					else {				/* 中间节点不冲突 */
						printf("中间节点不冲突\r\n");
						prev->next = next;
					}
		
					if (NULL == node) {
						printf("node为NULL\r\n");
					}
					
					task_addr			= (uint64_t)node;
					ready_flag = 1;
					break;
				}
		
			}
		
			if (ready_flag) {
				printf("node任务节点与线程池都不冲突\r\n");
				break;
			}
			
			usleep(50);				/* 短暂休眠,等待所有执行线程与其个任务不冲突 */
		}


		while (taskqueue_noconflict != NULL) {
			
			/* 阻塞等待线程池中有线程执行完毕(变为idle) */
			int 			fdn = epoll_wait(epollfd, pool->events_epoll, pool->th_num, -1);

			/* 遍历线程池,将任务注入线程 */
			for (int i = 0, j = 0; (j < fdn) && (i < pool->th_num) && (NULL != taskqueue_noconflict); i++) {	
				struct epoll_event * e = &pool->events_epoll[i];	/* 获取线程事件 */

				/* 空闲线程? */
				if (e->events & EPOLLIN) {
					atomic_dec(&pool->task_queued);
					int 			fd	= e->data.fd;

					ssize_t ret = read(fd, &ok, sizeof(uint64_t));
					if (ret == -1) {
						perror("read thread task queue");
					}
					assert(ok == OK_VALUE);

					struct thread_struct * thread;
					thread				= thread_pool_get_thread_by_fd(pool, fd);

					printf("----------------调试装--------------------------\r\n");
					/* 这里不能直接在for里用taskqueue = taskqueue->next
					 * 因为在执行这句语句之前可能执行任务的线程就被调度并且执行完毕
					 * 将这个task结构释放掉了,这时next就会成为无效指针
					 * 所以需要一个临时变量
					 */
					tmptask 			= taskqueue_noconflict->next;
					task_addr			= (uint64_t)taskqueue_noconflict;

					/* 任务防冲突id写入执行线程 */
					pool->repeat_ids[i] = taskqueue_noconflict->repeat_id;

					/* 将任务注入执行线程 */
					if (write(thread->eventfds[1], &task_addr, sizeof(uint64_t)) != sizeof(uint64_t))
						atomic_inc(&pool->task_error);

					/* 任务队列头指向下一个待执行任务 */
					taskqueue_noconflict			= tmptask;

					j++;

					break;
				}
			}
		}
	}

	return NULL;
}



/* 获取cpu核数 */
static int get_cpu_count()
{
	return sysconf(_SC_NPROCESSORS_ONLN);
}


/**
 *函数功能:		取消池中所有执行线程、等待池中所有执行线程执行完毕、
 		取消管理线程,等待管理线程执行完毕
 		是否对象所占内存
 		释放线程池中的任务等待队列
 */
void thread_pool_destory(struct thread_pool * pool)
{
	void *			ret;

	for (int i = 0; i < pool->th_num; i++)
		pthread_cancel(pool->threads[i].thread_id);

	for (int i = 0; i < pool->th_num; i++)
		pthread_join(pool->threads[i].thread_id, &ret);

	pthread_cancel(pool->manager);
	pthread_join(pool->manager, &ret);

	free(pool->threads);
	free(pool->events_epoll);
	free(pool->repeat_ids);
	thread_pool_event_destory(&pool->event_queue);
	thread_pool_event_destory(&pool->event_alldone);

	struct thread_task * task = pool->task_queue;

	while (task) {
		struct thread_task * tmp = task->next;
		thread_task_destroy(task, 0);
		task				= tmp;
	}
}


/**
 *函数功能:		创建线程池
 */
struct thread_pool * thread_pool_create(int thread_num)
{
	assert(sizeof(void *) == 8);

	if (thread_num == THREAD_NUM_CPU)
		thread_num = get_cpu_count();

	struct thread_pool * pool;

	if ((pool = malloc(sizeof(struct thread_pool))) == NULL)
		return NULL;

	pool->th_num = thread_num;
	pool->threads = NULL;
	pool->task_queue = NULL;
	atomic_set(&pool->task_total, 0);
	atomic_set(&pool->task_queued, 0);
	atomic_set(&pool->task_running, 0);
	atomic_set(&pool->task_done, 0);

	pool->threads = calloc(pool->th_num, sizeof(struct thread_struct));
	if (pool->threads == NULL)
		goto err;

	pool->events_epoll = calloc(pool->th_num, sizeof(struct epoll_event));
	if (pool->events_epoll == NULL)
		goto err1;

	pool->repeat_ids = calloc(pool->th_num, sizeof(unsigned long long));
	if (pool->repeat_ids == NULL)
		goto err2;

	if (thread_pool_event_init(&pool->event_queue) != 0)
		goto err3;

	if (thread_pool_event_init(&pool->event_alldone) != 0)
		goto err4;

	if (pthread_create(&pool->manager, NULL, thread_pool_manager, pool) != 0)
		goto err5;

	return pool;

	/*这种写法是不是太逗比了,但是写在每个if里感觉更糟糕 */

err5:
	thread_pool_event_destory(&pool->event_alldone);

err4:
	thread_pool_event_destory(&pool->event_queue);

err3:
	free(pool->repeat_ids);

err2:
	free(pool->events_epoll);

err1:
	free(pool->threads);

err:
	free(pool);
	return NULL;
}

/**
 *函数功能:		阻塞当前进程,等待所有执行线程执行任务完毕
 */
void thread_pool_wait_all(struct thread_pool * pool)
{
	thread_pool_event_lock(&pool->event_alldone);

	while (atomic_read(&pool->task_done) != atomic_read(&pool->task_total))
		thread_pool_event_wait(&pool->event_alldone);

	thread_pool_event_unlock(&pool->event_alldone);
}


/**
 *函数功能:		将任务注入,线程池待执行任务队列、通知管理线程有新的任务注入线程池
 */
static void _thread_pool_queue_task(struct thread_pool * pool, thread_task_t * task)
{
	thread_pool_event_lock(&pool->event_queue);
	task->next			= pool->task_queue;
	pool->task_queue	= task;
	task->task_status	= THREAD_TASK_STATUS_INQUEUE;
	thread_pool_event_notify(&pool->event_queue);
	thread_pool_event_unlock(&pool->event_queue);
	atomic_inc(&pool->task_total);
	atomic_inc(&pool->task_queued);
	task->task_id		= atomic_read(&pool->task_total);
}


/**
 *函数功能:		往线程任务队列注入一个未封装的业务
 *参数:		pool 线程池
 		func 待注入的任务
 		arg 任务预值参数
 */
int thread_pool_new_task(struct thread_pool * pool, task_func func, void * arg, unsigned long long repeat_id)
{
	if (pool == NULL || func == NULL)
		return - 1;

	thread_task_t * task = _thread_task_create(func, arg, repeat_id, THREAD_TASK_NO_RESULT);

	if (task == NULL)
		return - 1;

	_thread_pool_queue_task(pool, task);

	return 0;
}

/**
 *函数功能:		向线程池注入一个已经封装好的业务
 */
int thread_pool_queue_task(struct thread_pool * pool, thread_task_t * task)
{
	_thread_pool_queue_task(pool, task);

	return 0;
}

发布了67 篇原创文章 · 获赞 66 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/jacky128256/article/details/104329532