当需要利用线程大量处理任务时,使用线程池可以减小大量创建、销毁线程的开销,特别是任务处理时间短时更能节省系统资源。
线程池的基本原理是在任务执行开始前,就预先创建一定数量的线程放入线程列表(链表,数组,队列等)中,创建这些线程都是处于休眠状态。当任务到来后,从线程池中选择一个空闲的线程,用此线程执行,如果无空闲的线程则创建新的线程来处理,并将些线程加入线程池。任务执行完成之后,将线程重新阻塞,等待下一次任务。当一定量的线程处于阻塞状态时,自动销毁线程池中的部分的线程
thread_pool.h
#ifndef __THREAD_POOL__
#define __THREAD_POOL__
typedef void *(*handle_fun)(void *arg);
typedef struct
{
uint32_t min_th; /*保持的最少线程数*/
uint32_t cur_th; /*线程池中当前线程数*/
uint32_t max_th; /*允许的最大线程数*/
uint32_t free_th;
pthread_mutex_t pool_lock;
list_t *threads; /*list of threads*/
pthread_t monitor_th;
}thread_pool;
int has_cap_to_process_task_queue(thread_pool *pool);
int task_process(thread_pool *pool, process_fun fun, void *arg);
thread_pool *thread_pool_create(uint32_t min, uint32_t max);
#endif
thread_pool.c
/******************************************************************************
zgang 2013/9/10
******************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include "hm_types.h"
#include "hm_util.h"
#include "thread_pool.h"
typedef struct
{
pthread_t thread_id;
uint8_t is_busy;
uint8_t to_be_die;
pthread_cond_t cond;
pthread_mutex_t lock;
handle_fun proc;
void *arg;
thread_pool *pool;
listnode_t *node;
}thread_info;
#define LOCK_POOL(_pool) \
pthread_mutex_lock(&_pool->pool_lock)
#define UNLOCK_POOL(_pool) \
pthread_mutex_unlock(&_pool->pool_lock)
static void *work_thread(void *arg)
{
thread_info *info = (thread_info *)arg;
thread_pool *pool = info->pool;
listnode_t *node = info->node;
list_t *list = pool->threads;
while (1)
{
if (info->to_be_die)
{
break;
}
if (info->proc)
{
info->proc(info->arg);
info->is_busy = FALSE;
info->proc = NULL;
LOCK_POOL(pool);
node->data = info;
node->prev = list->tail;
node->next = NULL;
if (list->head == NULL)
list->head = node;
else
list->tail->next = node;
list->tail = node;
list->count++;
UNLOCK_POOL(pool);
}
pthread_mutex_lock(&info->lock);
pthread_cond_wait(&info->cond, &info->lock);
pthread_mutex_unlock(&info->lock);
}
}
/*从线程池中取出空闲线程*/
static thread_info *get_idle_thread(thread_pool *pool)
{
thread_info *idle = NULL;
listnode_t *node = NULL;
list_t *idle_list = NULL;
LOCK_POOL(pool);
idle_list = pool->threads;
if (idle_list->head == NULL || idle_list->count == 0)
{
UNLOCK_POOL(pool);
return NULL;
}
node = idle_list->head;
idle_list->head = node->next;
if (!idle_list->head)
idle_list->tail = NULL;
else
idle_list->head->prev = NULL;
idle_list->count--;
idle = node->data;
idle->is_busy = TRUE;
UNLOCK_POOL(pool);
return idle;
}
/*向线程池添加新的线程*/
static thread_info *add_new_thread_to_pool(thread_pool *pool)
{
thread_info *thread = NULL;
LOCK_POOL(pool);
if (pool->cur_th >= pool->max_th)
{
dpf("%d >= %d", pool->cur_th, pool->max_th);
UNLOCK_POOL(pool);
sleep(30);
return NULL;
}
UNLOCK_POOL(pool);
thread = (thread_info *)malloc(sizeof(thread_info));
if (thread == NULL)
{
dpf("memory error!");
sleep(30);
return NULL;
}
memset(thread, 0, sizeof(thread_info));
pthread_cond_init(&thread->cond, NULL);
pthread_mutex_init(&thread->lock, NULL);
thread->proc = NULL;
thread->arg = NULL;
LOCK_POOL(pool);
thread->pool = pool;
thread->node = listnode_add(pool->threads, (void *)thread);
UNLOCK_POOL(pool);
if (pthread_create(&thread->thread_id, NULL, work_thread, thread) != 0)
{
LOCK_POOL(pool);
listnode_delete(pool->threads, thread);
UNLOCK_POOL(pool);
dpf("create thread error!");
sleep(30);
return NULL;
}
LOCK_POOL(pool);
pool->cur_th++;
UNLOCK_POOL(pool);
usleep(10000);
return thread;
}
int task_process(thread_pool *pool, handle_fun fun, void *arg)
{
thread_info *thread = NULL;
thread = get_idle_thread(pool);
if (thread)
{
thread->is_busy = TRUE;
thread->proc = fun;
thread->arg = arg;
pthread_cond_signal(&thread->cond); /*唤醒线程*/
return 0;
}
else /*线程池中无空闲线程,则创建新的线程*/
{
thread = add_new_thread_to_pool(pool);
if (!thread)
{
thread->is_busy = TRUE;
thread->proc = fun;
thread->arg = arg;
pthread_cond_signal(&thread->cond);
return 0;
}
else
{
dpf("can't handle");
return 1;
}
}
}
int is_too_many_idle_threads(thread_pool *pool)
{
LOCK_POOL(pool);
if (pool->cur_th <= pool->min_th)
{
UNLOCK_POOL(pool);
return 0;
}
float free_thld = (float)(pool->threads->count) / pool->cur_th;
UNLOCK_POOL(pool);
if (free_thld > 0.5) // if half of threads are idle, kill some of them
return 1;
else
return 0;
}
/*从线程池中删除进程*/
void delete_thread_from_pool(thread_pool *pool)
{
thread_info *pthread = NULL;
LOCK_POOL(pool);
if (pool->cur_th <= pool->min_th)
{
UNLOCK_POOL(pool);
return;
}
UNLOCK_POOL(pool);
pthread = get_idle_thread(pool);
if (pthread)
{
LOCK_POOL(pool);
pool->cur_th--;
UNLOCK_POOL(pool);
pthread->to_be_die = TRUE;
while (!pthread->to_be_die)
{
usleep(1000);
pthread->to_be_die = TRUE;
}
pthread_cond_signal(&pthread->cond);
usleep(10000);
pthread_mutex_destroy(&pthread->lock);
pthread_cond_destroy(&pthread->cond);
free(pthread->node);
free(pthread);
}
}
/*监测线程数量*/
static void *monitor_thread(void *arg)
{
thread_pool *pool = (thread_pool *)arg;
while (1)
{
while (is_too_many_idle_threads(pool)) /*空闲线程过多,杀掉一部分*/
{
delete_thread_from_pool(pool);
}
sleep(15);
}
return NULL;
}
int has_cap_to_process_task_queue(thread_pool *pool)
{
int rt = 0;
LOCK_POOL(pool);
rt = pool->threads->count;
if (rt)
{
UNLOCK_POOL(pool);
return 1;
}
else if (pool->cur_th < pool->max_th)
{
UNLOCK_POOL(pool);
return 1;
}
else
{
UNLOCK_POOL(pool);
return 0;
}
}
static void free_thread_info(void *p)
{
free(p);
}
thread_pool *thread_pool_create(uint32_t min, uint32_t max)
{
int i = 0;
thread_pool *pool = NULL;
thread_info *thread = NULL;
pool = (thread_pool *)malloc(sizeof(thread_pool));
if (pool == NULL)
{
return NULL;
}
memset(pool, 0, sizeof(pool));
pool->min_th = min;
pool->max_th = max;
pool->cur_th = min;
pthread_mutex_init(&pool->pool_lock, NULL);
pool->threads = list_new();
pool->threads->del = free_thread_info;
for (i = 0; i < min; i++)
{
thread = (thread_info *)malloc(sizeof(thread_info));
if (thread == NULL)
{
list_delete(pool->threads);
free(pool);
return NULL;
}
memset(thread, 0, sizeof(thread_info));
pthread_cond_init(&thread->cond, NULL);
pthread_mutex_init(&thread->lock, NULL);
thread->proc = NULL;
thread->arg = NULL;
thread->pool = pool;
thread->node = listnode_add(pool->threads, (void *)thread);
if (pthread_create(&thread->thread_id, NULL, work_thread, thread) != 0)
{
list_delete(pool->threads);
return NULL;
}
pthread_detach(thread->thread_id);
usleep(50000);
}
if (pthread_create(&pool->monitor_th, NULL, monitor_thread, pool) != 0)
{
list_delete(pool->threads);
return NULL;
}
usleep(1000);
return pool;
}
typedef struct listnode
{
struct listnode *next;
struct listnode *prev;
void *data;
}listnode_t;
typedef void (*list_del_f)(void *val);
typedef struct list
{
listnode_t *head;
listnode_t *tail;
uint32_t count;
list_del_f del;
}list_t;
void list_delete(list_t *list)
{
listnode_t *node = NULL;
listnode_t *next = NULL;
for (node = list->head; node; node = node->next)
{
if (list->del)
{
(*list->del)(node->data);
}
free(node);
}
free(list);
}
list_t *list_new()
{
list_t *new = NULL;
new = malloc(sizeof(list_t));
memset(new, 0, sizeof(list_t));
return new;
}
listnode_t *listnode_new()
{
listnode_t *node = NULL;
node = (listnode_t *)malloc(sizeof(listnode_t));
if (node == NULL)
return NULL;
memset(node, 0, sizeof(listnode_t));
return node;
}
listnode_t * listnode_add(list_t *list, void *val)
{
listnode_t *node = NULL;
node = listnode_new();
if (node == NULL)
return NULL;
node->prev = list->tail;
node->data = val;
if (list->head == NULL)
list->head = node;
else
list->tail->next = node;
list->tail = node;
list->count++;
return node;
}
void listnode_delete(list_t *list, void *val)
{
listnode_t *node = NULL;
for (node = list->head; node; node = node->next)
{
if (node->data == val)
{
if (node->prev)
node->prev->next = node->next;
else
list->head = node->next;
if (node->next)
node->next->prev = node->prev;
else
list->tail = node->prev;
list->count--;
free(node);
break;
}
}
}