线程池是多个线程组成的线程队列和多个任务组成的任务队列总体管理的池子,对于一些需要一个时刻创建很多线程的场合,由于对CPU造成很大的负担,有可能是实现不了的,所以线程池起到了一个缓冲的作用,使用队列的思想进行排队处理任务。
代码框架主要如下,由线程池提供三个函数接口,分别为创建线程池,初始化线程池和注册任务(这三个接口其实还不完整,应该还需要销毁等接口,本文只是记录线程池的大概实现方法和思想)
主要分为三大类
/**@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
#include
#include
#include
#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;
主要分为两大类
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;
}
(可以理解为管理部分)
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);
}
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;
}
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;
}
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;
}
/**@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
#include "thread_pool.h"
#define LOG printf
void job_cb_fun(int param, void *arg)
{
LOG("%d --------------\n", param);
}
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;
}
主要是声明外部调用接口。
/**@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
本文章主要是通过代码编写简单实现线程池,代码部分还有很多地方设计不完善,但是可以大概了解线程池实现方法和应用。