线程池C代码实现(linux环境测试)

线程池C代码实现



前言

线程池是多个线程组成的线程队列和多个任务组成的任务队列总体管理的池子,对于一些需要一个时刻创建很多线程的场合,由于对CPU造成很大的负担,有可能是实现不了的,所以线程池起到了一个缓冲的作用,使用队列的思想进行排队处理任务。


一、代码实现框架

代码框架主要如下,由线程池提供三个函数接口,分别为创建线程池,初始化线程池和注册任务(这三个接口其实还不完整,应该还需要销毁等接口,本文只是记录线程池的大概实现方法和思想)
在这里插入图片描述

二、代码

1.对象定义

主要分为三大类

  1. 线程队列(线程对象节点定义和线程队列定义)
  2. 任务队列(任务对象节点定义和任务队列定义)
  3. 线程池管理
/**@file
 * @note CSDN Li Haoqin. All rights reserved
 * @brief 线程池源文件
 *
 *@author lihaoqin
 *@date 2020/10/10
 *
 *@version
 *  data        |version  |author               |message
 *  :-----      |:-----   |:-----               |:----
 *  2020/10/10  |V1.0.0   |lihaoqin             |创建代码文档
 *@warning
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "thread_pool.h"

#define MAX_THREAD_CNT (100u)
#define LOG printf

//线程对象节点定义
typedef struct THREADNODE
{
	pthread_t thread;
	int idx;
	int is_terminate;
	struct THREADNODE *next;
	struct THREADPOOL *thread_pool;
} THREADNODE, *ThreadQueuePtr;

//线程队列定义
typedef struct
{
	ThreadQueuePtr front, rear;
} LinkThreadQueue;

//任务对象节点定义
typedef struct JOBNODE
{
	JOB_CB_FUN job_cb_fun;
	int param;
	void *arg;
	struct JOBNODE *next;
} JOBNODE, *JobQueuePtr;

//任务队列定义
typedef struct
{
	JobQueuePtr front, rear;
} LinkJobQueue;

//线程池管理
typedef struct THREADPOOL
{
	int is_init;
	int thread_cnt;
	pthread_mutex_t mu;
	pthread_cond_t cond;
	LinkThreadQueue thread_queue;
	LinkJobQueue job_queue;
} THREADPOOL;

2.队列入队和出队

主要分为两大类

  1. 线程队列入队和出队
  2. 任务队列入队和出队
static int thread_enqueue(LinkThreadQueue *link, THREADNODE *node)
{
	if (NULL == link || NULL == node)
	{
		return -1;
	}
	if (NULL == link->rear)
	{
		return -2;
	}
	
	node->next = NULL;
	link->rear->next = node;
	link->rear = node;
	
	return 0;
}


static int thread_dequeue(LinkThreadQueue *link, THREADNODE **thread_node)
{
	THREADNODE *node = NULL;
	
	if (NULL == link)
	{
		return -1;
	}
	if (NULL == link->front || NULL == link->rear)
	{
		return -2;
	}
	if (link->front == link->rear)
	{
		return -3;
	}
	
	node = link->front->next;
	link->front->next = node->next;
	
	if (node == link->rear)
	{
		link->rear = link->front;
	}
	
	*(THREADNODE **)thread_node = node;
	
	return 0;
}

static int job_enqueue(LinkJobQueue *link, JOBNODE *node)
{
	if (NULL == link || NULL == node)
	{
		return -1;
	}
	if (NULL == link->rear)
	{
		return -2;
	}
	
	node->next = NULL;
	link->rear->next = node;
	link->rear = node;
	
	return 0;
}


static int job_dequeue(LinkJobQueue *link, JOBNODE **job_node)
{
	JOBNODE *node = NULL;
	
	if (NULL == link)
	{
		return -1;
	}
	if (NULL == link->front || NULL == link->rear)
	{
		return -2;
	}
	if (link->front == link->rear)
	{
		return -3;
	}
	
	node = link->front->next;
	link->front->next = node->next;
	
	if (node == link->rear)
	{
		link->rear = link->front;
	}
	
	*(JOBNODE **)job_node = node;
	
	return 0;
}

3.内部处理接口

(可以理解为管理部分)

static void *thread_process(void *arg)
{
	THREADNODE *thread_node = (THREADNODE *)arg;
	JOBNODE *job_node = NULL;
	
	while (1)
	{
		pthread_mutex_lock(&thread_node->thread_pool->mu);
		
		while (0 != job_dequeue(&thread_node->thread_pool->job_queue, &job_node))
		{
			if (1 == thread_node->is_terminate)
			{
				break;
			}
			pthread_cond_wait(&thread_node->thread_pool->cond, &thread_node->thread_pool->mu);
		}
		
		pthread_mutex_unlock(&thread_node->thread_pool->mu);
		if (1 == thread_node->is_terminate)
		{
			break;
		}
		
		if (NULL == job_node)
		{
			continue;
		}
		job_node->job_cb_fun(job_node->param, job_node->arg);
		free(job_node);
	}
	
	free(thread_node);
	pthread_exit(NULL);
}

4.对外接口

  1. 创建线程池:传入需要创建多少个线程作为线程池处理线程
int thread_pool_create(void **handle, int thread_cnt)
{
   THREADPOOL *thread_pool = NULL;
   
   if (NULL == handle)
   {
   	LOG("%s[%d] param is null\n", __FUNCTION__, __LINE__);
   	return -1;
   }
   if ((0 == thread_cnt) || (MAX_THREAD_CNT < thread_cnt))
   {
   	LOG("%s[%d] thread cnt error\n", __FUNCTION__, __LINE__);
   	return -2;
   }
   
   thread_pool = (THREADPOOL *)malloc(sizeof(THREADPOOL));
   memset(thread_pool, 0, sizeof(THREADPOOL));
   thread_pool->thread_cnt = thread_cnt;
   
   *(THREADPOOL **)handle = thread_pool;
   
   return 0;
}
  1. 线程池初始化接口:调用此接口使得线程池开始工作
int thread_pool_init(void *handle)
{
	THREADNODE *thread_node = NULL;
	JOBNODE *job_node = NULL;
	THREADPOOL *thread_pool = (THREADPOOL *)handle;
	int idx = 0;
	int ret = 0;
	
	if (NULL == thread_pool)
	{
		LOG("%s[%d] param is null\n", __FUNCTION__, __LINE__);
		return -1;
	}
	if (1 == thread_pool->is_init)
	{
		LOG("%s[%d] thread pool is already init\n", __FUNCTION__, __LINE__);
		return -2;
	}
	
	pthread_mutex_t mutex_tmp = PTHREAD_MUTEX_INITIALIZER;
	memcpy(&thread_pool->mu, &mutex_tmp, sizeof(thread_pool->mu));
	
	pthread_cond_t cond_tmp = PTHREAD_COND_INITIALIZER;
	memcpy(&thread_pool->cond, &cond_tmp, sizeof(thread_pool->cond));
	
	thread_node = (THREADNODE *)malloc(sizeof(THREADNODE));
	if (NULL == thread_node)
	{
		LOG("%s[%d] thread node malloc failed\n", __FUNCTION__, __LINE__);
		return -3;
	}
	job_node = (JOBNODE *)malloc(sizeof(JOBNODE));
	if (NULL == job_node)
	{
		LOG("%s[%d] job node malloc failed\n", __FUNCTION__, __LINE__);
		return -4;
	}
	thread_pool->thread_queue.front = thread_node;
	thread_pool->thread_queue.rear = thread_node;
	
	thread_pool->job_queue.front = job_node;
	thread_pool->job_queue.rear = job_node;
	
	for (idx = 0; idx < thread_pool->thread_cnt; idx++)
	{
		thread_node = (THREADNODE *)malloc(sizeof(THREADNODE));
		if (NULL == thread_node)
		{
			LOG("%s[%d] thread %d node malloc failed\n", __FUNCTION__, __LINE__, idx);
			return -5;
		}
		memset(thread_node, 0, sizeof(thread_node));
		
		thread_node->idx = idx;
		thread_node->thread_pool = thread_pool;
		ret = pthread_create(&thread_node->thread, NULL, thread_process, thread_node);
		if (0 != ret)
		{
			LOG("%s[%d] thread  %d create failed\n", __FUNCTION__, __LINE__, idx);
			return -6;
		}
		
		ret = thread_enqueue(&thread_pool->thread_queue, thread_node);
		if (0 != ret )
		{
			LOG("%s[%d] thread_enqueue %d failed\n", __FUNCTION__, __LINE__, idx);
			return -7;
		}
	}
	
	thread_pool->is_init = 1;
	
	return 0;
}
  1. 任务注册接口(注册任务,传入回调函数和参数)
int register_job(void *handle, JOB_CB_FUN cb, int param, void *arg)
{
	THREADPOOL *thread_pool = (THREADPOOL *)handle;
	JOBNODE *job_node = NULL;
	int ret = 0;
	
	if (NULL == thread_pool)
	{
		LOG("%s[%d] param is null\n", __FUNCTION__, __LINE__);
		return -1;
	}
	if (0 == thread_pool->is_init)
	{
		LOG("%s[%d] thread pool is already init\n", __FUNCTION__, __LINE__);
		return -2;
	}
	
	job_node = (JOBNODE *)malloc(sizeof(JOBNODE));
	if (NULL == job_node)
	{
		LOG("%s[%d] malloc job node failed\n", __FUNCTION__, __LINE__);
		return -3;
	}
	
	job_node->job_cb_fun = cb;
	job_node->param = param;
	job_node->arg = arg;
	
	pthread_mutex_lock(&thread_pool->mu);
	
	ret = job_enqueue(&thread_pool->job_queue, job_node);
	if (NULL == job_node)
	{
		LOG("%s[%d] job_enqueue failed\n", __FUNCTION__, __LINE__);
		pthread_mutex_unlock(&thread_pool->mu);
		return -4;
	}
	
	pthread_cond_signal(&thread_pool->cond);
	pthread_mutex_unlock(&thread_pool->mu);
	
	return 0;
}

4.app测试代码

/**@file
 * @note CSDN Li Haoqin. All rights reserved
 * @brief app线程池测试文件
 *
 *@author lihaoqin
 *@date 2020/10/10
 *
 *@version
 *  data        |version  |author               |message
 *  :-----      |:-----   |:-----               |:----
 *  2020/10/10  |V1.0.0   |lihaoqin             |创建代码文档
 *@warning
 */
 
#include <stdio.h>
#include "thread_pool.h"


#define LOG printf

void job_cb_fun(int param, void *arg)
{
	LOG("%d --------------\n", param);
	usleep(1000);                       /**< 加一个小延时,模拟任务堵塞时间 */
}

int main(int argc, char *argv[])
{
	void *handle;
	int ret = 0;
	int i = 0;
	
	ret = thread_pool_create(&handle, atoi(argv[1]));
	if (0 != ret)
	{
		LOG("%s[%d] thread_pool_create failed with ret %d\n", __FUNCTION__, __LINE__, ret);
		return -1;
	}
	
	ret = thread_pool_init(handle);
	if (0 != ret)
	{
		LOG("%s[%d] thread_pool_init failed with ret %d\n", __FUNCTION__, __LINE__, ret);
		return -2;
	}
	
	for (i = 0; i < 100000; i++)
	{
		register_job(handle, job_cb_fun, i, NULL);
	}
	getchar();
	
	return 0;
}

5.线程池头文件

主要是声明外部调用接口。

/**@file
 * @note CSDN Li Haoqin. All rights reserved
 * @brief 线程池头文件
 *
 *@author lihaoqin
 *@date 2020/10/10
 *
 *@version
 *  data        |version  |author               |message
 *  :-----      |:-----   |:-----               |:----
 *  2020/10/10  |V1.0.0   |lihaoqin             |创建代码文档
 *@warning
 */

#ifndef __THREAD_POOL_H_
#define __THREAD_POOL_H_

#ifdef __cplusplus
extern "C" {
#endif

typedef void (*JOB_CB_FUN)(int param, void *arg);

int thread_pool_create(void **handle, int thread_cnt);
int thread_pool_init(void *handle);
int register_job(void *handle, JOB_CB_FUN cb, int param, void *arg);

#ifdef __cplusplus
}
#endif

#endif

总结

本文章主要是通过代码编写简单实现线程池,代码部分还有很多地方设计不完善,但是可以大概了解线程池实现方法和应用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值