⽤c语⾔实现_线程池原理详解及如何⽤C语⾔实现线程池
线程池是⼀种多线程处理形式,⼤多⽤于⾼并发服务器上,它能合理有效的利⽤⾼并发服务器上的线程资源;线程与进程⽤于处理各项分⽀⼦功能,我们通常的操作是:接收消息 ==> 消息分类 ==> 线程创建 ==> 传递消息到⼦线程 ==> 线程分离 ==> 在⼦线程中执⾏任务 ==>任务结束退出;
对⼤多数⼩型局域⽹的通信来说,上述⽅法⾜够满⾜需求;但当我们的通信范围扩⼤到⼴域⽹或⼤型局域⽹通信中时,我们将⾯临⼤量消息频繁请求服务器;在这种情况下,创建与销毁线程都已经成为⼀种奢侈的开销,特别对于嵌⼊式服务器来说更应保证内存资源的合理利⽤;
因此,线程池技术应运⽽⽣;线程池允许⼀个线程可以多次复⽤,且每次复⽤的线程内部的消息处理可以不相同,将创建与销毁的开销省去⽽不必来⼀个请求开⼀个线程;
结构讲解:
线程池是⼀个抽象的概念,其内部由任务队列,⼀堆线程,管理者线程组成;
我们将以上图为例,实现⼀个最基础的线程池,接下来将分部分依次讲解;讲解顺序为:1.线程池总体结构 2.线程数组 3.任务队列 4.管理者线程 5.使⽤线程池接⼝的例⼦
⼀、线程池总体结构
这⾥讲解线程池在逻辑上的结构体;看下⽅代码,该结构体threadpool_t中包含线程池状态信息,任务队列信息以及多线程操作中的互斥锁;在任务结构体中包含了⼀个可以放置多种不同任务函数的函数指针,⼀个传⼊该任务函数的void*类型的参数;
注意:在使⽤时需要将你的消息分类处理函数装⼊任务的(*function);然后放置到任务队列并通知空闲线程;
线程池状态信息:描述当前线程池的基本信息,如是否开启、最⼩线程数、最⼤线程数、存活线程数、忙线程数、待销毁线程数等… …
任务队列信息:描述当前任务队列基本信息,如最⼤任务数、队列不为满条件变量、队列不为空条件变量等… …
多线程互斥锁:保证在同⼀时间点上只有⼀个线程在任务队列中取任务并修改任务队列信息、修改线程池信息;
函数指针:在打包消息阶段,将分类后的消息处理函数放在(*function);
void*类型参数:⽤于传递消息处理函数需要的信息;
/*任务*/
typedef struct {
void *(*function)(void *);
void *arg;
} threadpool_task_t;
/*线程池管理*/
struct threadpool_t{
pthread_mutex_t lock; /* 锁住整个结构体 */
pthread_mutex_t thread_counter; /* ⽤于使⽤忙线程数时的锁 */
pthread_cond_t queue_not_full; /* 条件变量,任务队列不为满 */
pthread_cond_t queue_not_empty; /* 任务队列不为空 */
pthread_t *threads; /* 存放线程的tid,实际上就是管理了线 数组 */
pthread_t admin_tid; /* 管理者线程tid */
threadpool_task_t *task_queue; /* 任务队列 */
/
*线程池信息*/
int min_thr_num; /* 线程池中最⼩线程数 */
int max_thr_num; /* 线程池中最⼤线程数 */
int live_thr_num; /* 线程池中存活的线程数 */
int busy_thr_num; /* 忙线程,正在⼯作的线程 */
int wait_exit_thr_num; /* 需要销毁的线程数 */
/*任务队列信息*/
int queue_front; /* 队头 */
int queue_rear; /* 队尾 */
int queue_size;
/* 存在的任务数 */
int queue_max_size; /* 队列能容纳的最⼤任务数 */
/*线程池状态*/
int shutdown; /* true为关闭 */
};
**/*创建线程池*/**
threadpool_t *
threadpool_create(int min_thr_num, int max_thr_num, int queue_max_size) { /* 最⼩线程数 最⼤线程数 最⼤任务数*/
int i;
threadpool_t *pool = NULL;
do
{
/* 线程池空间开辟 */
if ((pool=(threadpool_t *)malloc(sizeof(threadpool_t))) == NULL)
{
printf("malloc threadpool false; ");
break;
}
/*信息初始化*/
pool->min_thr_num = min_thr_num;
pool->max_thr_num = max_thr_num;
pool->busy_thr_num = 0;
pool->live_thr_num = min_thr_num;
pool->wait_exit_thr_num = 0;
pool->queue_front = 0;
pool->queue_rear = 0;
pool->queue_size = 0;
pool->queue_max_size = queue_max_size;
pool->shutdown = false;
/* 根据最⼤线程数,给⼯作线程数组开空间,清0 */
pool->threads = (pthread_t *)malloc(sizeof(pthread_t)*max_thr_num);
if (pool->threads == NULL)
{
printf("malloc threads false;");
break;
}
memset(pool->threads, 0, sizeof(pthread_t)*max_thr_num);
/* 队列开空间 */
pool->task_queue =
(threadpool_task_t *)malloc(sizeof(threadpool_task_t)*queue_max_size); if (pool->task_queue == NULL)
{
printf("malloc task queue false;");
break;嵌入式多线程编程
}
/* 初始化互斥锁和条件变量 */
if ( pthread_mutex_init(&(pool->lock), NULL) != 0 ||
pthread_mutex_init(&(pool->thread_counter), NULL) !=0 ||
pthread_cond_init(&(pool->queue_not_empty), NULL) !=0 ||
pthread_cond_init(&(pool->queue_not_full), NULL) !=0)
{
printf("init lock or cond false;");
break;
}
/* 启动min_thr_num个⼯作线程 */
for (i=0; i
{
/
* pool指向当前线程池 threadpool_thread函数在后⾯讲解 */
pthread_create(&(pool->threads[i]), NULL, threadpool_thread, (void *)pool);
printf("start thread ", (unsigned int)pool->threads[i]);
}
/* 管理者线程 admin_thread函数在后⾯讲解 */
pthread_create(&(pool->admin_tid), NULL, admin_thread, (void *)pool);
return pool;
} while(0);
/* 释放pool的空间 */
threadpool_free(pool);
return NULL;
}
⼆、线程数组
线程数组实际上是在线程池初始化时开辟的⼀段存放⼀堆线程tid的空间,在逻辑上形成⼀个池,⾥⾯放置着提前创建的线程;这段空间中包含了正在⼯作的线程,等待⼯作的线程(空闲线程),等待被销毁的线程,申明但没有初始化的线程空间;
/*⼯作线程*/
void *
threadpool_thread(void *threadpool)
{
threadpool_t *pool = (threadpool_t *)threadpool;
threadpool_task_t task;
while (true)
{
pthread_mutex_lock(&(pool->lock));
/* ⽆任务则阻塞在 “任务队列不为空” 上,有任务则跳出 */
while ((pool->queue_size == 0) && (!pool->shutdown))
{
printf("thread 0x%x is waiting ", (unsigned int)pthread_self()); pthread_cond_wait(&(pool->queue_not_empty), &(pool->lock)); /* 判断是否需要清除线程,⾃杀功能 */
if (pool->wait_exit_thr_num > 0)
{
pool->wait_exit_thr_num--;
/* 判断线程池中的线程数是否⼤于最⼩线程数,是则结束当前线程 */ if (pool->live_thr_num > pool->min_thr_num)
{
printf("thread 0x%x is exiting ", (unsigned int)pthread_self()); pool->live_thr_num--;
pthread_mutex_unlock(&(pool->lock));
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论