线程池

thread_pool.h

/*************************************************
 *
 *   file name:thread_pool.h
 *   author   :momolyl@126.com
 *   date     :2024/06/10
 *   brief    :线程池相关函数的头文件
 *   note     :None
 *
 *   CopyRight (c) 2024    momolyl@126.com    All Right Reseverd
 *
 **************************************************/
#ifndef _THREAD_POOL_H_
#define _THREAD_POOL_H_

#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>

#include <errno.h>
#include <pthread.h>

#define MAX_WAITING_TASKS 1000 // 处于等待状态的线程数量最大为1000
#define MAX_ACTIVE_THREADS 20  // 活跃的线程数量

// 任务结点  单向链表的节点,类型
struct task
{
	void *(*do_task)(void *arg); // 任务函数指针  指向线程要执行的任务  格式是固定的
	void *arg;					 // 需要传递给任务的参数,如果不需要,则NULL

	struct task *next; // 指向下一个任务结点的指针
};

// 线程池的管理结构体
typedef struct thread_pool
{
	pthread_mutex_t lock; // 互斥锁
	pthread_cond_t cond;  // 条件量

	bool shutdown; // 是否需要销毁线程池

	struct task *task_list; // 用于存储任务的链表

	pthread_t *tids; // 用于记录线程池中线程的ID

	unsigned max_waiting_tasks; // 线程池中线程的数量最大值
	unsigned waiting_tasks;		// 处于等待状态的线程数量
	unsigned active_threads;	// 正在活跃的线程数量
} thread_pool;

/*************************************************
 *
 *   func name     :init_pool
 *   brief         :初始化线程池
 *   func parameter:
 *                  @pool:待初始化的线程池指针
 *                  @threads_number:要创建的线程数量
 *   return        :None
 *   note          :None
 *   func author   :momolyl@126.com
 *   date          :2024/06/10
 *   version       :V1.0
 **************************************************/
// 初始化线程池
bool init_pool(thread_pool *pool, unsigned int threads_number);
/*************************************************
 *
 *   func name     :add_task
 *   brief         :在线程池的任务链表中添加任务
 *   func parameter:
 *                  @pool:线程池指针
 *                  @do_task:任务函数指针
 *                  @arg:任务函数的参数
 *   return        :None
 *   note          :None
 *   func author   :momolyl@126.com
 *   date          :2024/06/10
 *   version       :V1.0
 **************************************************/
// 向线程池中添加任务
bool add_task(thread_pool *pool, void *(*do_task)(void *arg), void *task);
/*************************************************
 *
 *   func name     :add_thread
 *   brief         :向线程池加入新线程
 *   func parameter:
 *                  @pool:线程池指针
 *                  @additional_threads:要添加的线程数量
 *
 *   return        :None
 *   note          :None
 *   func author   :momolyl@126.com
 *   date          :2024/06/10
 *   version       :V1.0
 **************************************************/
// 先线程池中添加线程
int add_thread(thread_pool *pool, unsigned int additional_threads_number);

/*************************************************
 *
 *   func name     :remove_thread
 *   brief         :删除线程池中的线程数量
 *   func parameter:
 *                  @pool:线程池指针
 *                  @removing_threads:要删除的线程数量
 *
 *   return        :None
 *   note          :None
 *   func author   :momolyl@126.com
 *   date          :2024/06/10
 *   version       :V1.0
 **************************************************/
// 从线程池中删除线程
int remove_thread(thread_pool *pool, unsigned int removing_threads_number);
/*************************************************
 *
 *   func name     :destroy_pool
 *   brief         :销毁线程池
 *   func parameter:
 *                  @pool:待销毁的线程池指针
 *
 *   return        :None
 *   note          :None
 *   func author   :momolyl@126.com
 *   date          :2024/06/10
 *   version       :V1.0
 **************************************************/
// 销毁线程池
bool destroy_pool(thread_pool *pool);
/*************************************************
 *
 *   func name     :routine
 *   brief         :线程要执行的任务函数
 *   func parameter:
 *                  @arg:线程任务参数
 *
 *   return        :None
 *   note          :None
 *   func author   :momolyl@126.com
 *   date          :2024/06/10
 *   version       :V1.0
 **************************************************/
// 任务函数
void *routine(void *arg);

#endif

thread_pool.c


/*************************************************
 *
 *   file name:thread_pool.c
 *   author   :momolyl@126.com
 *   date     :2024/06/10
 *   brief    :为线程池相关函数
 *   note     :None
 *
 *   CopyRight (c) 2024    momolyl@126.com    All Right Reseverd
 *
 **************************************************/
#include "thread_pool.h"

// 收到信号后要处理的任务
void handler(void *arg)
{
	printf("[%u] is ended.\n", // 打印线程本身的ID
		   (unsigned)pthread_self());

	pthread_mutex_unlock((pthread_mutex_t *)arg); // 线程释放互斥锁
}
/*************************************************
 *
 *   func name     :routine
 *   brief         :线程要执行的任务函数
 *   func parameter:
 *                  @arg:线程任务参数
 *
 *   return        :None
 *   note          :None
 *   func author   :momolyl@126.com
 *   date          :2024/06/10
 *   version       :V1.0
 **************************************************/
// 线程要执行的任务
void *routine(void *arg)
{
// 调试
#ifdef DEBUG
	printf("[%u] is started.\n",
		   (unsigned)pthread_self());
#endif

	thread_pool *pool = (thread_pool *)arg; // 把需要传递给线程任务的参数进行备份
	struct task *p;							// 创建任务结构体变量

	while (1)
	{
		/*
		** push a cleanup functon handler(), make sure that
		** the calling thread will release the mutex properly
		** even if it is cancelled during holding the mutex.
		**
		** NOTE:
		** pthread_cleanup_push() is a macro which includes a
		** loop in it, so if the specified field of codes that
		** paired within pthread_cleanup_push() and pthread_
		** cleanup_pop() use 'break' may NOT break out of the
		** truely loop but break out of these two macros.
		** see line 61 below.
		*/
		//================================================//
		pthread_cleanup_push(handler, (void *)&pool->lock); // 处理资源释放和清理工作
		pthread_mutex_lock(&pool->lock);					// 线程上互斥锁
		//================================================//

		// 1, no task, and is NOT shutting down, then wait
		while (pool->waiting_tasks == 0 && !pool->shutdown) // 当待处理任务列表为空且线程池无需销毁时,进入循环状态
		{
			pthread_cond_wait(&pool->cond, &pool->lock); //
		}

		// 2, no task, and is shutting down, then exit
		if (pool->waiting_tasks == 0 && pool->shutdown == true) // 如果线程池需要销毁
		{
			pthread_mutex_unlock(&pool->lock); // 线程解锁互斥锁
			pthread_exit(NULL);				   // CANNOT use 'break';//退出线程
		}

		// 3, have some task, then consume it
		p = pool->task_list->next;		 // 将任务链表中的首结点指向的任务,给到任务指针p
		pool->task_list->next = p->next; // 将任务链表的头节点指向原首结点的下一个节点
		pool->waiting_tasks--;			 // 等待处理的任务数量减一

		//================================================//
		pthread_mutex_unlock(&pool->lock); // 线程解锁
		pthread_cleanup_pop(0);			   // 不取消清理函数,也不执行
		//================================================//

		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); // 禁止其他线程取消该线程
		(p->do_task)(p->arg);								  // 线程执行任务
		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);  // 允许其他线程取消该线程

		free(p); // 释放任务指针
	}

	pthread_exit(NULL); // 退出线程
}
/*************************************************
 *
 *   func name     :init_pool
 *   brief         :初始化线程池
 *   func parameter:
 *                  @pool:待初始化的线程池指针
 *                  @threads_number:要创建的线程数量
 *   return        :None
 *   note          :None
 *   func author   :momolyl@126.com
 *   date          :2024/06/10
 *   version       :V1.0
 **************************************************/
// 初始化线程池
bool init_pool(thread_pool *pool, unsigned int threads_number)
{
	// 初始化互斥锁
	pthread_mutex_init(&pool->lock, NULL);

	// 初始化条件量
	pthread_cond_init(&pool->cond, NULL);

	// 销毁标志
	pool->shutdown = false; // 不销毁

	// 给链表的节点申请堆内存
	pool->task_list = malloc(sizeof(struct task));

	// 申请堆内存,用于存储创建出来的线程的ID
	pool->tids = malloc(sizeof(pthread_t) * MAX_ACTIVE_THREADS);

	// 错误处理,对malloc进行错误处理
	if (pool->task_list == NULL || pool->tids == NULL)
	{
		perror("allocate memory error"); // 输出错误原因
		return false;
	}

	// 对任务链表中的节点的指针域进行初始化
	pool->task_list->next = NULL;

	// 设置线程池中线程数量的最大值
	pool->max_waiting_tasks = MAX_WAITING_TASKS;

	// 设置等待线程处理的任务的数量为0,说明现在没有任务
	pool->waiting_tasks = 0;

	// 设置线程池中活跃的线程的数量
	pool->active_threads = threads_number;

	int i;

	// 循环创建活跃线程
	for (i = 0; i < pool->active_threads; i++)
	{
		// 创建线程  把线程的ID存储在申请的堆内存
		if (pthread_create(&((pool->tids)[i]), NULL,
						   routine, (void *)pool) != 0)
		{
			perror("create threads error");
			return false;
		}

// 用于调试
#ifdef DEBUG
		printf("[%u]:[%s] ==> tids[%d]: [%u] is created.\n",
			   (unsigned)pthread_self(), __FUNCTION__,
			   i, (unsigned)pool->tids[i]);
#endif
	}

	return true;
}
/*************************************************
 *
 *   func name     :add_task
 *   brief         :在线程池的任务链表中添加任务
 *   func parameter:
 *                  @pool:线程池指针
 *                  @do_task:任务函数指针
 *                  @arg:任务函数的参数
 *   return        :None
 *   note          :None
 *   func author   :momolyl@126.com
 *   date          :2024/06/10
 *   version       :V1.0
 **************************************************/
// 在线程池的任务链表中添加任务
bool add_task(thread_pool *pool,
			  void *(*do_task)(void *arg), void *arg)
{
	// 给任务链表节点申请内存
	struct task *new_task = malloc(sizeof(struct task));
	if (new_task == NULL)
	{
		perror("allocate memory error");
		return false;
	}

	new_task->do_task = do_task; // 将任务函数的指针放入任务结构体中
	new_task->arg = arg;		 // 将任务函数的参数放入任务结构体中
	new_task->next = NULL;		 // 指针域设置为NULL

	//============ LOCK =============//
	pthread_mutex_lock(&pool->lock); // 线程上互斥锁
	//===============================//

	// 说明要处理的任务的数量大于能处理的任务数量
	if (pool->waiting_tasks >= MAX_WAITING_TASKS)
	{
		pthread_mutex_unlock(&pool->lock); // 线程解锁互斥锁

		fprintf(stderr, "too many tasks.\n"); // 打印错误原因
		free(new_task);						  // 释放新任务的结构体指针

		return false;
	}

	struct task *tmp = pool->task_list; // 临时备份线程池任务列表的头节点用于遍历

	// 遍历链表,找到单向链表的尾节点
	while (tmp->next != NULL)
		tmp = tmp->next;

	// 把新的要处理的任务插入到链表的尾部  尾插
	tmp->next = new_task;

	// 要处理的任务的数量+1
	pool->waiting_tasks++;

	//=========== UNLOCK ============//
	pthread_mutex_unlock(&pool->lock); // 线程解锁互斥锁
//===============================//

// 调试
#ifdef DEBUG
	printf("[%u][%s] ==> a new task has been added.\n",
		   (unsigned)pthread_self(), __FUNCTION__);
#endif

	// 唤醒第一个处于阻塞队列中的线程
	pthread_cond_signal(&pool->cond);
	return true;
}
/*************************************************
 *
 *   func name     :add_thread
 *   brief         :向线程池加入新线程
 *   func parameter:
 *                  @pool:线程池指针
 *                  @additional_threads:要添加的线程数量
 *
 *   return        :None
 *   note          :None
 *   func author   :momolyl@126.com
 *   date          :2024/06/10
 *   version       :V1.0
 **************************************************/
// 向线程池加入新线程
int add_thread(thread_pool *pool, unsigned additional_threads)
{
	// 判断需要添加的新线程的数量是否为0
	if (additional_threads == 0)
		return 0;

	// 计算线程池中总线程的数量
	unsigned total_threads =
		pool->active_threads + additional_threads;

	int i, actual_increment = 0;

	//
	for (i = pool->active_threads; i < total_threads && i < MAX_ACTIVE_THREADS; i++) // 循环创建线程,创建数量不能大于原线程数量加上要添加的线程数量,且不大于最大活跃线程数量
	{
		// 创建新线程
		if (pthread_create(&((pool->tids)[i]),
						   NULL, routine, (void *)pool) != 0) // 线程创建失败的错误处理
		{
			perror("add threads error");

			// no threads has been created, return fail
			if (actual_increment == 0) // 如果实际新增的线程数量为0则退出循环
				return -1;

			break;
		}
		actual_increment++;

#ifdef DEBUG // 调试
		printf("[%u]:[%s] ==> tids[%d]: [%u] is created.\n",
			   (unsigned)pthread_self(), __FUNCTION__,
			   i, (unsigned)pool->tids[i]);
#endif
	}

	// 记录此时线程池中活跃线程的总数
	pool->active_threads += actual_increment;
	return actual_increment; // 返回实际新增的线程数量
}
/*************************************************
 *
 *   func name     :remove_thread
 *   brief         :删除线程池中的线程数量
 *   func parameter:
 *                  @pool:线程池指针
 *                  @removing_threads:要删除的线程数量
 *
 *   return        :None
 *   note          :None
 *   func author   :momolyl@126.com
 *   date          :2024/06/10
 *   version       :V1.0
 **************************************************/
// 删除线程
int remove_thread(thread_pool *pool, unsigned int removing_threads)
{
	if (removing_threads == 0)		 // 如果要删除的线程数量为0
		return pool->active_threads; // 则返回线程池中活跃的线程数量

	int remaining_threads = pool->active_threads - removing_threads;   // 剩余线程数量=活跃线程数量-要删除的线程数量
	remaining_threads = remaining_threads > 0 ? remaining_threads : 1; // 剩余的线程数量要大于等于1

	int i;
	for (i = pool->active_threads - 1; i > remaining_threads - 1; i--) // 循环删除线程,直到达到剩余线程数量为止,减一的目的是因为i为循环中的数组下标,下标从0开始
	{
		errno = pthread_cancel(pool->tids[i]); // 取消线程

		if (errno != 0) // 线程取消失败做错误处理
			break;

#ifdef DEBUG // 调试
		printf("[%u]:[%s] ==> cancelling tids[%d]: [%u]...\n",
			   (unsigned)pthread_self(), __FUNCTION__,
			   i, (unsigned)pool->tids[i]);
#endif
	}

	if (i == pool->active_threads - 1)
		return -1;
	else
	{
		pool->active_threads = i + 1;
		return i + 1;
	}
}
/*************************************************
 *
 *   func name     :destroy_pool
 *   brief         :销毁线程池
 *   func parameter:
 *                  @pool:待销毁的线程池指针
 *
 *   return        :None
 *   note          :None
 *   func author   :momolyl@126.com
 *   date          :2024/06/10
 *   version       :V1.0
 **************************************************/
bool destroy_pool(thread_pool *pool) // 销毁线程池
{
	// 1, activate all threads
	pool->shutdown = true;				 // 线程池销毁标志
	pthread_cond_broadcast(&pool->cond); // 唤醒线程池中所有线程,然后终止线程

	// 2, wait for their exiting
	int i;
	for (i = 0; i < pool->active_threads; i++)
	{
		errno = pthread_join(pool->tids[i], NULL); // 循环等待回收线程资源
		if (errno != 0)
		{
			printf("join tids[%d] error: %s\n",
				   i, strerror(errno));
		}
		else
			printf("[%u] is joined\n", (unsigned)pool->tids[i]);
	}

	// 3, free memories
	free(pool->task_list); // 释放线程池任务列表的堆内存
	free(pool->tids);	   // 释放线程池中线程句柄的堆内存
	free(pool);			   // 释放线程池指针

	return true;
}

main.c线程池函数使用示例

/*************************************************
 *
 *   file name:main.c
 *   author   :momolyl@126.com
 *   date     :2024/06/10
 *   brief    :线程池相关函数的使用示例
 *   note     :None
 *
 *   CopyRight (c) 2024    momolyl@126.com    All Right Reseverd
 *
 **************************************************/
#include "thread_pool.h"

void *mytask(void *arg)
{
	int n = (int)arg;

	printf("[%u][%s] ==> job will be done in %d sec...\n",
		   (unsigned)pthread_self(), __FUNCTION__, n);

	sleep(n);

	printf("[%u][%s] ==> job done!\n",
		   (unsigned)pthread_self(), __FUNCTION__);

	return NULL;
}

void *count_time(void *arg)
{
	int i = 0;
	while (1)
	{
		sleep(1);
		printf("sec: %d\n", ++i);
	}
}

int main(void)
{
	pthread_t a;
	pthread_create(&a, NULL, count_time, NULL); // 创建计时线程

	// 1, initialize the pool
	thread_pool *pool = malloc(sizeof(thread_pool)); // 为线程池管理结构体申请堆内存
	init_pool(pool, 2);								 // 初始化线程池并申请两个活跃线程

	// 2, throw tasks
	printf("throwing 3 tasks...\n");
	add_task(pool, mytask, (void *)(rand() % 10)); // 依次向线程池中添加任务,共计三个
	add_task(pool, mytask, (void *)(rand() % 10));
	add_task(pool, mytask, (void *)(rand() % 10));

	// 3, check active threads number
	printf("current thread number: %d\n",
		   remove_thread(pool, 0)); // 检查线程池中当前活跃的线程数量
	sleep(9);

	// 4, throw tasks
	printf("throwing another 2 tasks...\n");
	add_task(pool, mytask, (void *)(rand() % 10)); // 依次向线程池中添加任务,共计两个
	add_task(pool, mytask, (void *)(rand() % 10));

	// 5, add threads
	add_thread(pool, 2); // 向线程池中添加两个线程

	sleep(5);

	// 6, remove threads
	printf("remove 3 threads from the pool, "
		   "current thread number: %d\n",
		   remove_thread(pool, 3)); // 移除线程池中的三个线程并查看当前线程池中的线程数量

	// 7, destroy the pool
	destroy_pool(pool); // 销毁线程池
	return 0;
}

posted @   铃是铃铛的铃  阅读(21)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示