linux下c/c++实例之十三C实现的简单的线程池

一、简介

        线程池就是有一堆已经创建好了的线程,初始它们都处于空闲等待状态,当有新的任务需要处理的时候,就从这个池子里面取一个空闲等待的线程来处理该任务,当处理完成了就再次把该线程放回池中,以供后面的任务使用。当池子里的线程全都处理忙碌状态时,线程池中没有可用的空闲等待线程,此时,根据需要选择创建一个新的线程并置入池中,或者通知任务线程池忙,稍后再试。
       为什么要用线程池,线程的创建和销毁比之进程的创建和销毁是轻量级的,但是当一个应用需要频繁的创建和销毁线程,而任务执行的时间又非常短,这样线程创建和销毁的带来的开销就不容忽视,这是就可以使用线程池了(若线程创建和销毁时间相比任务执行时间可以忽略不计,则不必要使用线程池了)。线程池的好处就在于线程复用,一个任务处理完成后,当前线程可以直接处理下一个任务,而不是销毁后再创建,非常适用于连续产生大量并发任务的场合。
       
线程池工作原理(线程池负责线程的创建,销毁和任务处理参数传递、唤醒和等待):
(1)创建若干线程,置入线程池
(2)任务达到时,从线程池取空闲线程
(3)取得了空闲线程,立即进行任务处理
(4)否则新建一个线程,并置入线程池,执行(3)
(5)如果创建失败或者线程池已满,根据设计策略选择返回错误或将任务置入处理队列,等待处理
(6)销毁线程池

二、详解

1、简单的线程池代码一

(1)threadpool.h:

#ifndef _THREADPOOL_H_
#define _THREADPOOL_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

#define THWK_F_CLEAN    1    /* 设置此标志着threadpool正在进行清理操作,此时线程退出。 */
#define THWK_F_RUNNING    2    /* 设置这个标志主要是为了避免一个race condition,后述。 */
#define EINVAL 1
#define EBUSY 2

struct thread_worker_arg {
    void (*action)(void*);    /* user programmer指定的实际函数 */
    void *what;        /* action的参数 */
};

struct thread_worker {
    pthread_t id;            /* just as its name */
    struct thread_worker_arg arg;    /* 用于给sleepy_wrapper()传送参数,后述。 */
    pthread_mutex_t lock;        /* 用于实现线程池内空闲线程的休眠,它实际上并不保护什么临界区。 */
    struct thread_worker *next;    /* 用于链表线程池内的其他线程 */
    unsigned long long delay;    /* 未用,计划用于测量调度延迟。 */
    unsigned long flags;        /* 标志,后述。 */
};

struct thread_pool {
    pthread_mutex_t lock;        /* 用于同步对于thread_pool自身的访问操作 */
    struct thread_worker *first;    /* 所有线程链接于此 */
    int total;            /* 总线程数 */
    int current_nr;            /* 池内空闲线程数 */
};
struct thread_pool* thread_pool_create(int nr_to_create, pthread_attr_t *attr);
int thread_pool_lend(struct thread_pool *pool, void (*action)(void*), void* what, struct thread_worker **worker);
int thread_pool_giveback(struct thread_pool *pool, struct thread_worker *worker);
int thread_pool_clean(struct thread_pool *pool);

int thread_pool_is_running(struct thread_worker *worker);
void thread_pool_activate(struct thread_worker *worker);
#endif
(2)threadpool.c:
#include "threadpool.h"        /* #include了所有必要的系统头文件 */

/* 未用,计划用于测量调度延迟。 */
inline unsigned long long get_ticks(void)
{
    //    __asm__ ("rdtsc");

    return 0ULL;
}

/* 用于支持线程在被取消时的必要清理操作。 */
static void sleepy_wrapper_cleanup(void *voidp)
{
    struct thread_worker *worker = voidp;

    pthread_mutex_unlock(&worker->lock);
    free(worker);
}

/* 这就是线程池内线程的执行函数了。 */
static void* sleepy_wrapper(void *voidp)
{
    struct thread_worker *worker = voidp;

    while (1) {
        pthread_cleanup_push(sleepy_wrapper_cleanup, worker); /* 预设置上一个清理函数,防止线程取消时内存泄漏。 */
        pthread_mutex_lock(&worker->lock); /* 空闲线程应该休眠于此,这个mutex在创建thread pool时就锁住了。或者本循环结束时锁住。 */
        worker->delay = get_ticks() - worker->delay; /* 暂时无用。 */
        if (THWK_F_CLEAN & worker->flags) /* 线程池正在清理本身,所以线程至此就退出了。 */
            goto done; /* 你可能觉得这个goto用得有些多余,但如果不这样编译就会提示句法错误,因为pthread_cleanup_{push,pop}是用宏实现的!你可以参考一下它们的实现。 */
        worker->flags |= THWK_F_RUNNING; /* 后述。 */
        if (worker->arg.action) /* 进行线程实际的工作 */
            worker->arg.action(worker->arg.what);
done:
        pthread_mutex_unlock(&worker->lock); /* 解锁这个mutex,允许这个thread的下一次使用 */
        pthread_cleanup_pop(0);
        if (THWK_F_CLEAN & worker->flags) /* 清理线程池 */
            break;
        pthread_mutex_lock(&worker->lock); /* 先锁住这个锁,以让本循环开头的pthread_mutex_lock()使线程进入休眠。这个调用应该是成功的,否则就会引用deadlock。 */
        worker->flags &= ~THWK_F_RUNNING; /* 设计这个标志的意义在于防止有线程激活操作在以上unlock/lock之间发生,如果这样的话,就会引起deadlock,激活操作的实现后述。 */
    }
    pthread_exit(0);
}

/* 无需废话的函数。 */
pthread_t thread_pool_rawid(struct thread_worker *worker)
{
    return worker->id;
}

/* 如果线程被取消了,通知线程池忘记它,目前的实现很简单。*/
void thread_pool_forget(struct thread_pool *pool, struct thread_worker *worker)
{
    pool->total--;
}

/* 线程激活操作 */
void thread_pool_activate(struct thread_worker *worker)
{
    worker->delay = get_ticks();
    while (thread_pool_is_running(worker)) /* 防止出现deadlock */
        ;
    pthread_mutex_unlock(&worker->lock); /* 使sleepy_wrapper()内循环开头部分的lock()操作返回,即线程得以唤醒执行实际的action(what)。 */
}

/* 另一个无须废话的函数 */
int thread_pool_is_running(struct thread_worker *worker)
{
    return (worker->flags & THWK_F_RUNNING);
}

/* 从线程池中借出一个线程,其实就是一个从链表头中摘出thread_worker的简单函数 */
int thread_pool_lend(struct thread_pool *pool, void (*action)(void*), void* what, struct thread_worker **worker)
{
    if (!action || !pool || !worker)
        return -EINVAL;

    pthread_mutex_lock(&pool->lock);
    *worker = pool->first;
    if (worker) {
        (*worker)->arg.action = action;
        (*worker)->arg.what = what;
        pool->first = (*worker)->next;
        (*worker)->next = NULL;
        pool->current_nr--;
    }
    pthread_mutex_unlock(&pool->lock);
    return 0;
}

/* 向线程池里归还一个thread,头插法插入thread_worker链表。 */
int thread_pool_giveback(struct thread_pool *pool, struct thread_worker *worker)
{
    if (!pool || !worker)
        return -EINVAL;

    while (thread_pool_is_running(worker))
        ;

    pthread_mutex_lock(&pool->lock);
    worker->next = pool->first;
    pool->first = worker;
    worker->arg.action = NULL;
    worker->arg.what = NULL;
    pool->current_nr++;
    pthread_mutex_unlock(&pool->lock);

    return 0;
}

/* 虽然有点长,但仍然是无须废话:线程池创建 */
struct thread_pool* thread_pool_create(int nr_to_create, pthread_attr_t *attr)
{
    struct thread_pool *pool;
    struct thread_worker *worker;
    int i, chk;

    if (!nr_to_create)
        return NULL;

    pool = malloc(sizeof(struct thread_pool));
    if (!pool)
        return NULL;

    pool->first = NULL;
    pool->total = 0;
    pthread_mutex_init(&pool->lock, NULL);

    for (i=0; i<nr_to_create; ++i) {
        worker = malloc(sizeof(struct thread_worker));
        if (!worker)
            break;
        memset(worker, 0, sizeof(struct thread_worker));

        pthread_mutex_init(&worker->lock, NULL);
        pthread_mutex_lock(&worker->lock);

        chk = pthread_create(&worker->id, attr, sleepy_wrapper, (void*)worker);
        if (chk) {
            pthread_mutex_unlock(&worker->lock);
            pthread_mutex_destroy(&worker->lock);
            free(worker);
            break;
        }
        worker->next = pool->first;
        pool->first = worker;
    }
    
    pool->total = i;
    pool->current_nr = i;
    if (0 == i) {
        pthread_mutex_destroy(&pool->lock);
        free(pool);
        pool = NULL;
    }
    return pool;
}

/* 清理线程池。 */
int thread_pool_clean(struct thread_pool *pool)
{
    struct thread_worker *worker;

    pthread_mutex_lock(&pool->lock);
    if (pool->total != pool->current_nr) {
        pthread_mutex_unlock(&pool->lock);
        return -EBUSY;
    }

    while (NULL != (worker = pool->first)) {
        worker->flags = THWK_F_CLEAN; /* this is =, rather than |= ! */
        pthread_mutex_unlock(&worker->lock);
        pthread_join(worker->id, NULL);
        pool->first = worker->next;
        pthread_mutex_destroy(&worker->lock);
        free(worker);
    }

    pthread_mutex_unlock(&pool->lock);
    pthread_mutex_destroy(&pool->lock);
    free(pool);
    return 0;
}
(3)main.c:
#include "threadpool.h"

unsigned long long sum(unsigned long long start, unsigned long long end)
{
    unsigned long long sum;

    sum = 0;
    for (; start<=end; ++start)
        sum += start;

    return sum;
}

struct per_sum {
    unsigned long long sum, start, end;
    pthread_mutex_t lock;
    pthread_cond_t cond;
};

void threaded_sum(void *voidp)
{
    struct per_sum *per_sum = voidp;

    printf("thread %p start\n", voidp);

    if (!per_sum) {
        //printf("per_sum == NULL\n");
        return;
    }
    printf("+++++++++++++++start=%lld, end=%lld\n", per_sum->start, per_sum->end);
    per_sum->sum = sum(per_sum->start, per_sum->end);
    per_sum->start = per_sum->end = 0;
    pthread_mutex_lock(&per_sum->lock);
    printf("thread %p exit, end=%lld\n", voidp, per_sum->end);
    pthread_cond_signal(&per_sum->cond);
    pthread_mutex_unlock(&per_sum->lock);
}

int main(void)
{
    #define NR_THREADS    2
    struct thread_worker* workers[NR_THREADS];
    struct per_sum per_sums[NR_THREADS];
    struct thread_pool *pool;
    int i;

    unsigned long long start = 0, end = 0;
    unsigned long long result = 0;
    unsigned long long delta = 10;

    printf("thread_pool is running...\n");

    printf("+++++++++++++++init+++++++++++++++\n");
    printf("thread_pool create...\n");
    pool = thread_pool_create(NR_THREADS, NULL);
    if(!pool) exit(-1);

    for (i=0; i<NR_THREADS; ++i) {
        if (pthread_mutex_init(&per_sums[i].lock, NULL)) {
            printf("failed init mutex\n");
            exit(3);
        }
        if (pthread_cond_init(&per_sums[i].cond, NULL)) {
            printf("failed init cond\n");
            exit(4);
        }
        if (thread_pool_lend(pool, threaded_sum, (void*)&per_sums[i], &workers[i])) {
            printf("failed to lend thread %d\n", i);
            exit(5);
        }
    }

    start = 0;
    printf("++++++set value++++result=%lld++++\n", result);
    printf("thread_pool activate...\n");
    /* activate threads */
    for (i=0; i<NR_THREADS; i++) {
        per_sums[i].start = start;
        per_sums[i].end = per_sums[i].start + delta;
        start = per_sums[i].end + 1;
        thread_pool_activate(workers[i]);
    }
    printf("thread_pool wait...\n");
    for (i=0; i<NR_THREADS; i++) {
        pthread_mutex_lock(&per_sums[i].lock);
        while (per_sums[i].end != 0)
            pthread_cond_wait(&per_sums[i].cond, &per_sums[i].lock);
        result += per_sums[i].sum;
        pthread_mutex_unlock(&per_sums[i].lock);
    }
    /* activate threads again */
    printf("++++++set value again++++result=%lld++++\n", result);
    printf("thread_pool activate again...\n");
    for (i=0; i<NR_THREADS; i++) {
        per_sums[i].start = start;
        per_sums[i].end = per_sums[i].start + delta;
        start = per_sums[i].end + 1;
        thread_pool_activate(workers[i]);
    }
    end = per_sums[NR_THREADS-1].end;

    for (i=0; i<NR_THREADS; i++) {
        pthread_mutex_lock(&per_sums[i].lock);
        while (per_sums[i].end != 0)
            pthread_cond_wait(&per_sums[i].cond, &per_sums[i].lock);
        result += per_sums[i].sum;
        pthread_mutex_unlock(&per_sums[i].lock);
    }
    printf("thread_pool giveback...\n");
    for (i=0; i<NR_THREADS; ++i) {
        if (thread_pool_giveback(pool, workers[i])) {
            printf("failed to giveback thread %d\n", i);
            exit(6);
        }
        pthread_mutex_destroy(&per_sums[i].lock);
        pthread_cond_destroy(&per_sums[i].cond);
    }
    printf("thread_pool clean...\n");
    thread_pool_clean(pool);
    printf("*******sum = %lld******\n", result);
    return 0;
}
(4)编译运行:
gcc -o main main.c threadpool.c  -lpthread
./main

2、简单的线程池代码二

(1)threadpool.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <pthread.h>
#include <assert.h>

typedef struct worker
{
    void *(*process) (void *arg);
    void *arg;
    struct worker *next;
} CThread_worker;

typedef struct
{
    pthread_mutex_t queue_lock;
    pthread_cond_t queue_ready;
    CThread_worker *queue_head;
    int shutdown;
    pthread_t *threadid;
    int max_thread_num;
    int cur_queue_size;
} CThread_pool;

int pool_add_worker (void *(*process) (void *arg), void*arg);
void *thread_routine (void *arg);
static CThread_pool *pool = NULL;

void pool_init (int max_thread_num)
{
    pool = (CThread_pool *) malloc (sizeof(CThread_pool));
    pthread_mutex_init (&(pool->queue_lock), NULL);
    pthread_cond_init (&(pool->queue_ready), NULL);

    pool->queue_head = NULL;

    pool->max_thread_num = max_thread_num;
    pool->cur_queue_size = 0;

    pool->shutdown = 0;

    pool->threadid = (pthread_t *) malloc (max_thread_num * sizeof(pthread_t));
    int i = 0;
    for (i = 0; i < max_thread_num; i++) {
        pthread_create (&(pool->threadid[i]), NULL, thread_routine, NULL);
    }
}

int pool_add_worker (void *(*process) (void *arg), void*arg)
{
    CThread_worker *newworker = (CThread_worker *) malloc (sizeof(CThread_worker));
    newworker->process = process;
    newworker->arg = arg;
    newworker->next = NULL;

    pthread_mutex_lock (&(pool->queue_lock));
    CThread_worker *member = pool->queue_head;
    if (member != NULL) {
        while (member->next != NULL)
            member = member->next;
        member->next = newworker;
    }
    else {
        pool->queue_head = newworker;
    }
    assert (pool->queue_head != NULL);
    pool->cur_queue_size++;
    pthread_mutex_unlock (&(pool->queue_lock));
    pthread_cond_signal (&(pool->queue_ready));
    return 0;
}

int pool_destroy ()
{
    if (pool->shutdown)
        return -1;
    pool->shutdown = 1;
    pthread_cond_broadcast (&(pool->queue_ready));
    int i;
    for (i = 0; i < pool->max_thread_num; i++)
        pthread_join (pool->threadid[i], NULL);
    free (pool->threadid);

    CThread_worker *head = NULL;
    while (pool->queue_head != NULL) {
        head = pool->queue_head;
        pool->queue_head = pool->queue_head->next;
        free (head);
    }
    pthread_mutex_destroy(&(pool->queue_lock));
    pthread_cond_destroy(&(pool->queue_ready));
    free (pool);
    pool=NULL;
    return 0;
}

void *thread_routine (void *arg)
{
    printf ("starting thread 0x%x\n", pthread_self ());
    while (1) {
        pthread_mutex_lock (&(pool->queue_lock));
        while (pool->cur_queue_size == 0 && !pool->shutdown) {
            printf ("thread 0x%x is waiting\n", pthread_self ());
            pthread_cond_wait (&(pool->queue_ready), &(pool->queue_lock));
        }

        if (pool->shutdown) {
            pthread_mutex_unlock (&(pool->queue_lock));
            printf ("thread 0x%x will exit\n", pthread_self ());
            pthread_exit (NULL);
        }

        printf ("thread 0x%x is starting to work\n", pthread_self ());
        assert (pool->cur_queue_size != 0);
        assert (pool->queue_head != NULL);

        pool->cur_queue_size--;
        CThread_worker *worker = pool->queue_head;
        pool->queue_head = worker->next;
        pthread_mutex_unlock (&(pool->queue_lock));

        (*(worker->process)) (worker->arg);
        free (worker);
        worker = NULL;
    }
    pthread_exit (NULL);
}
(2)main.c:
#include <stdio.h>
#include <stdlib.h>

void *myprocess (void *arg)
{
    printf ("threadid is 0x%x, working on task %d\n", pthread_self (),*(int *) arg);
    sleep (1);
    return NULL;
}

int main (int argc, char **argv)
{
    pool_init (3);
    int *workingnum = (int *) malloc (sizeof (int) * 10);
    int i;
    for (i = 0; i < 10; i++) {
        workingnum[i] = i;
        pool_add_worker (myprocess, &workingnum[i]);
    }
    sleep (5);
    pool_destroy ();
    free (workingnum);
    return 0;
}
(3)编译运行:
gcc -o main main.c threadpool.c  -lpthread
./main

3、简单的线程池代码三

(1)thread_pool.h:
#ifndef __THREAD_POOL_H
#define __THREAD_POOL_H

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <pthread.h>
#include <signal.h>

#include "tsqueue.h"

#ifndef BOOL
#define BOOL int
#endif

#ifndef TRUE
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE 0
#endif

#define BUSY_THRESHOLD 0.5	//(busy thread)/(all thread threshold)
#define MANAGE_INTERVAL 30	//tp manage thread sleep interval, every MANAGE_INTERVAL seconds, manager thread will try to recover idle threads as BUSY_THRESHOLD

typedef struct tp_thread_info_s TpThreadInfo;
typedef struct tp_thread_pool_s TpThreadPool;

typedef void (*process_job)(void *arg);

//thread info
struct tp_thread_info_s {
	pthread_t thread_id; //thread id num
	BOOL is_busy; //thread status:true-busy;flase-idle
	pthread_cond_t thread_cond;
	pthread_mutex_t thread_lock;
	process_job proc_fun;
	void *arg;
	TpThreadPool *tp_pool;
};

//main thread pool struct
struct tp_thread_pool_s {
	unsigned min_th_num; //min thread number in the pool
	unsigned cur_th_num; //current thread number in the pool
	unsigned max_th_num; //max thread number in the pool
	pthread_mutex_t tp_lock;
	pthread_cond_t tp_cond;
	pthread_mutex_t loop_lock;
	pthread_cond_t loop_cond;
	
	TpThreadInfo *thread_info;
	TSQueue *idle_q; //idle queue
	BOOL stop_flag; //whether stop the threading pool
	
	pthread_t manage_thread_id; //manage thread id num
	float busy_threshold; //
	unsigned manage_interval; //
};

TpThreadPool *tp_create(unsigned min_num, unsigned max_num);
int tp_init(TpThreadPool *pTp);
void tp_loop(TpThreadPool *pTp);
void tp_exit(TpThreadPool *pTp);
void tp_close(TpThreadPool *pTp, BOOL wait);
int tp_process_job(TpThreadPool *pTp, process_job proc_fun, void *arg);

float tp_get_busy_threshold(TpThreadPool *pTp);
int tp_set_busy_threshold(TpThreadPool *pTp, float bt);
unsigned tp_get_manage_interval(TpThreadPool *pTp);
int tp_set_manage_interval(TpThreadPool *pTp, unsigned mi); //mi - manager interval time, in second

#endif
(2)thread_pool.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>

#include "thread_pool.h"

//#define __DEBUG__

#ifdef __DEBUG__
#define DEBUG(format,...)	printf(format,##__VA_ARGS__)
#else
#define DEBUG(format,...) 
#endif

static TpThreadInfo *tp_add_thread(TpThreadPool *pTp, process_job proc_fun, void *job);
static int tp_delete_thread(TpThreadPool *pTp); 
static int tp_get_tp_status(TpThreadPool *pTp); 

static void *tp_work_thread(void *pthread);
static void *tp_manage_thread(void *pthread);

/**
 * user interface. creat thread pool.
 * para:
 * 	num: min thread number to be created in the pool
 * return:
 * 	thread pool struct instance be created successfully
 */
TpThreadPool *tp_create(unsigned min_num, unsigned max_num) {
    TpThreadPool *pTp;
    pTp = (TpThreadPool*) malloc(sizeof(TpThreadPool));

    memset(pTp, 0, sizeof(TpThreadPool));

    //init member var
    pTp->min_th_num = min_num;
    pTp->cur_th_num = min_num;
    pTp->max_th_num = max_num;
    pthread_mutex_init(&pTp->tp_lock, NULL);
    pthread_cond_init(&pTp->tp_cond, NULL);
    pthread_mutex_init(&pTp->loop_lock, NULL);
    pthread_cond_init(&pTp->loop_cond, NULL);

    //malloc mem for num thread info struct
    if (NULL != pTp->thread_info)
        free(pTp->thread_info);
    pTp->thread_info = (TpThreadInfo*) malloc(sizeof(TpThreadInfo) * pTp->max_th_num);
    memset(pTp->thread_info, 0, sizeof(TpThreadInfo) * pTp->max_th_num);

    return pTp;
}

/**
 * member function reality. thread pool init function.
 * para:
 * 	pTp: thread pool struct instance ponter
 * return:
 * 	true: successful; false: failed
 */
int tp_init(TpThreadPool *pTp) {
    int i;
    int err;
    TpThreadInfo *pThi;

    //init_queue(&pTp->idle_q, NULL);
    pTp->idle_q = ts_queue_create();
    pTp->stop_flag = FALSE;
    pTp->busy_threshold = BUSY_THRESHOLD;
    pTp->manage_interval = MANAGE_INTERVAL;

    //create work thread and init work thread info
    for (i = 0; i < pTp->min_th_num; i++) {
        pThi = pTp->thread_info + i;
        pThi->tp_pool = pTp;
        pThi->is_busy = FALSE;
        pthread_cond_init(&pThi->thread_cond, NULL);
        pthread_mutex_init(&pThi->thread_lock, NULL);
        pThi->proc_fun = NULL;
        pThi->arg = NULL;
        ts_queue_enq_data(pTp->idle_q, pThi);

        err = pthread_create(&pThi->thread_id, NULL, tp_work_thread, pThi);
        if (0 != err) {
            perror("tp_init: create work thread failed.");
            ts_queue_destroy(pTp->idle_q);
            return -1;
        }
    }

    //create manage thread
    err = pthread_create(&pTp->manage_thread_id, NULL, tp_manage_thread, pTp);
    if (0 != err) {//clear_queue(&pTp->idle_q);
        ts_queue_destroy(pTp->idle_q);
        fprintf(stderr, "tp_init: creat manage thread failed\n");
        return 0;
    }

    //wait for all threads are ready
    while(i++ < pTp->cur_th_num){
        pthread_mutex_lock(&pTp->tp_lock);
        pthread_cond_wait(&pTp->tp_cond, &pTp->tp_lock);
        pthread_mutex_unlock(&pTp->tp_lock);
    }
    DEBUG("All threads are ready now\n");
    return 0;
}

/**
 * let the thread pool wait until {@link #tp_exit} is called
 * @params:
 *	pTp: pointer of thread pool
 * @return
 *	none
 */
void tp_run(TpThreadPool *pTp){
    pthread_mutex_lock(&pTp->loop_lock);
    pthread_cond_wait(&pTp->loop_cond, &pTp->loop_lock);
    pthread_mutex_unlock(&pTp->loop_lock);
    tp_close(pTp, TRUE);
}

/**
 * let the thread pool exit, this function will wake up {@link #tp_loop}
 * @params:
 *	pTp: pointer of thread pool
 * @return
 *	none
 */
void tp_exit(TpThreadPool *pTp){
    pthread_cond_signal(&pTp->loop_cond);
}

/**
 * member function reality. thread pool entirely close function.
 * para:
 * 	pTp: thread pool struct instance ponter
 * return:
 */
void tp_close(TpThreadPool *pTp, BOOL wait) {
    unsigned i;

    pTp->stop_flag = TRUE;
    if (wait) {
        DEBUG("current number of threads: %u", pTp->cur_th_num);
        for (i = 0; i < pTp->cur_th_num; i++) {
            pthread_cond_signal(&pTp->thread_info[i].thread_cond);
        }
        for (i = 0; i < pTp->cur_th_num; i++) {
            if(0 != pthread_join(pTp->thread_info[i].thread_id, NULL)){
                perror("pthread_join");
            }
            //DEBUG("join a thread success.\n");
            pthread_mutex_destroy(&pTp->thread_info[i].thread_lock);
            pthread_cond_destroy(&pTp->thread_info[i].thread_cond);
        }
    } else {
        //close work thread
        for (i = 0; i < pTp->cur_th_num; i++) {
            kill((pid_t)pTp->thread_info[i].thread_id, SIGKILL);
            pthread_mutex_destroy(&pTp->thread_info[i].thread_lock);
            pthread_cond_destroy(&pTp->thread_info[i].thread_cond);
        }
    }
    //close manage thread
    kill((pid_t)pTp->manage_thread_id, SIGKILL);
    pthread_mutex_destroy(&pTp->tp_lock);
    pthread_cond_destroy(&pTp->tp_cond);
    pthread_mutex_destroy(&pTp->loop_lock);
    pthread_cond_destroy(&pTp->loop_cond);

    //clear_queue(&pTp->idle_q);
    ts_queue_destroy(pTp->idle_q);
    //free thread struct
    free(pTp->thread_info);
    pTp->thread_info = NULL;
}

/**
 * member function reality. main interface opened.
 * after getting own worker and job, user may use the function to process the task.
 * para:
 * 	pTp: thread pool struct instance ponter
 *	worker: user task reality.
 *	job: user task para
 * return:
 */
int tp_process_job(TpThreadPool *pTp, process_job proc_fun, void *arg) {
    TpThreadInfo *pThi ;
    //fill pTp->thread_info's relative work key
    pThi = (TpThreadInfo *) ts_queue_deq_data(pTp->idle_q);
    if(pThi){
        DEBUG("Fetch a thread from pool.\n");
        pThi->is_busy = TRUE;
        pThi->proc_fun = proc_fun;
        pThi->arg = arg;
        //let the thread to deal with this job
        DEBUG("wake up thread %u\n", pThi->thread_id);
        pthread_cond_signal(&pThi->thread_cond);
    }
    else{
        //if all current thread are busy, new thread is created here
        if(!(pThi = tp_add_thread(pTp, proc_fun, arg))){
            DEBUG("The thread pool is full, no more thread available.\n");
            return -1;
        }
        /* should I wait? */
        //pthread_mutex_lock(&pTp->tp_lock);
        //pthread_cond_wait(&pTp->tp_cond, &pTp->tp_lock);
        //pthread_mutex_unlock(&pTp->tp_lock);

        DEBUG("No more idle thread, a new thread is created.\n");
    }
    return 0;
}

/**
 * member function reality. add new thread into the pool and run immediately.
 * para:
 * 	pTp: thread pool struct instance ponter
 * 	proc_fun:
 * 	job:
 * return:
 * 	pointer of TpThreadInfo
 */
static TpThreadInfo *tp_add_thread(TpThreadPool *pTp, process_job proc_fun, void *arg) {
    int err;
    TpThreadInfo *new_thread;

    pthread_mutex_lock(&pTp->tp_lock);
    if (pTp->max_th_num <= pTp->cur_th_num){
        pthread_mutex_unlock(&pTp->tp_lock);
        return NULL;
    }

    //malloc new thread info struct
    new_thread = pTp->thread_info + pTp->cur_th_num;
    pTp->cur_th_num++;
    pthread_mutex_unlock(&pTp->tp_lock);

    new_thread->tp_pool = pTp;
    //init new thread's cond & mutex
    pthread_cond_init(&new_thread->thread_cond, NULL);
    pthread_mutex_init(&new_thread->thread_lock, NULL);

    //init status is busy, only new process job will call this function
    new_thread->is_busy = TRUE;
    new_thread->proc_fun = proc_fun;
    new_thread->arg = arg;

    err = pthread_create(&new_thread->thread_id, NULL, tp_work_thread, new_thread);
    if (0 != err) {
        perror("tp_add_thread: pthread_create");
        free(new_thread);
        return NULL;
    }
    return new_thread;
}

/**
 * member function reality. delete idle thread in the pool.
 * only delete last idle thread in the pool.
 * para:
 * 	pTp: thread pool struct instance ponter
 * return:
 * 	true: successful; false: failed
 */
int tp_delete_thread(TpThreadPool *pTp) {
    unsigned idx;
    TpThreadInfo *pThi;
    TpThreadInfo tT;

    //current thread num can't < min thread num
    if (pTp->cur_th_num <= pTp->min_th_num)
        return -1;
    //all threads are busy
    pThi = (TpThreadInfo *) ts_queue_deq_data(pTp->idle_q);
    if(!pThi)
        return -1;

    //after deleting idle thread, current thread num -1
    pthread_mutex_lock(&pTp->tp_lock);
    pTp->cur_th_num--;
    /** swap this thread to the end, and free it! **/
    memcpy(&tT, pThi, sizeof(TpThreadInfo));
    memcpy(pThi, pTp->thread_info + pTp->cur_th_num, sizeof(TpThreadInfo));
    memcpy(pTp->thread_info + pTp->cur_th_num, &tT, sizeof(TpThreadInfo));
    pthread_mutex_unlock(&pTp->tp_lock);

    //kill the idle thread and free info struct
    kill((pid_t)tT.thread_id, SIGKILL);
    pthread_mutex_destroy(&tT.thread_lock);
    pthread_cond_destroy(&tT.thread_cond);

    return 0;
}

/**
 * internal interface. real work thread.
 * @params:
 * 	arg: args for this method
 * @return:
 *	none
 */
static void *tp_work_thread(void *arg) {
    TpThreadInfo *pTinfo = (TpThreadInfo *) arg;
    TpThreadPool *pTp = pTinfo->tp_pool;

    //wake up waiting thread, notify it I am ready
    pthread_cond_signal(&pTp->tp_cond);
    while (!(pTp->stop_flag)) {
        //process
        if(pTinfo->proc_fun){
            DEBUG("thread %u is running\n", pTinfo->thread_id);
            pTinfo->proc_fun(pTinfo->arg);
            //thread state shoulde be set idle after work
            pTinfo->is_busy = FALSE;
            pTinfo->proc_fun = NULL;
            //I am idle now
            ts_queue_enq_data(pTp->idle_q, pTinfo);
        }

        //wait cond for processing real job.
        DEBUG("thread %u is waiting for a job\n", pTinfo->thread_id);
        pthread_mutex_lock(&pTinfo->thread_lock);
        pthread_cond_wait(&pTinfo->thread_cond, &pTinfo->thread_lock);
        pthread_mutex_unlock(&pTinfo->thread_lock);
        DEBUG("thread %u end waiting for a job\n", pTinfo->thread_id);

        if(pTinfo->tp_pool->stop_flag){
            DEBUG("thread %u stop\n", pTinfo->thread_id);
            break;
        }
    }
    DEBUG("Job done, thread %u is idle now.\n", pTinfo->thread_id);
}

/**
 * member function reality. get current thread pool status:idle, normal, busy, .etc.
 * para:
 * 	pTp: thread pool struct instance ponter
 * return:
 * 	0: idle; 1: normal or busy(don't process)
 */
int tp_get_tp_status(TpThreadPool *pTp) {
    float busy_num = 0.0;
    int i;

    //get busy thread number
    busy_num = pTp->cur_th_num - ts_queue_count(pTp->idle_q);

    DEBUG("Current thread pool status, current num: %u, busy num: %u, idle num: %u\n", pTp->cur_th_num, (unsigned)busy_num, ts_queue_count(pTp->idle_q));
    if(busy_num / (pTp->cur_th_num) < pTp->busy_threshold)
        return 0;//idle status
    else
        return 1;//busy or normal status
}

/**
 * internal interface. manage thread pool to delete idle thread.
 * para:
 * 	pthread: thread pool struct ponter
 * return:
 */
static void *tp_manage_thread(void *arg) {
    TpThreadPool *pTp = (TpThreadPool*) arg;//main thread pool struct instance

    //1?
    sleep(pTp->manage_interval);

    do {
        if (tp_get_tp_status(pTp) == 0) {
            do {
                if (!tp_delete_thread(pTp))
                    break;
            } while (TRUE);
        }//end for if

        //1?
        sleep(pTp->manage_interval);
    } while (!pTp->stop_flag);
    return NULL;
}

float tp_get_busy_threshold(TpThreadPool *pTp){
    return pTp->busy_threshold;
}

int tp_set_busy_threshold(TpThreadPool *pTp, float bt){
    if(bt <= 1.0 && bt > 0.)
        pTp->busy_threshold = bt;
}

unsigned tp_get_manage_interval(TpThreadPool *pTp){
    return pTp->manage_interval;
}

int tp_set_manage_interval(TpThreadPool *pTp, unsigned mi){
    pTp->manage_interval = mi;
}
(3)tsqueue.h:
#ifndef B_TS_QUEUE_H__
#define B_TS_QUEUE_H__

#ifndef BOOL
#define BOOL int
#endif

#ifndef TRUE
#define TRUE 1
#endif 

#ifndef FALSE
#define FALSE 0
#endif

#ifdef __cplusplus
extern "C" {
#endif

typedef struct ts_queue_item TSQItem;

struct ts_queue_item{
    void *data;
    struct ts_queue_item *next;
};

typedef struct ts_queue TSQueue;

struct ts_queue{
    TSQItem *head;
    TSQItem *tail;
    pthread_mutex_t lock;

    TSQItem *cqi_freelist;
    pthread_mutex_t cqi_freelist_lock;

    unsigned count;
};

TSQueue *ts_queue_create();
void ts_queue_destroy(TSQueue *cq);
void ts_queue_init(TSQueue *cq);
TSQItem *ts_queue_item_new(TSQueue *cq);
void ts_queue_item_free(TSQueue *cq, TSQItem *item);

TSQItem *ts_queue_head(TSQueue *cq);
TSQItem *ts_queue_tail(TSQueue *cq);
TSQItem *ts_queue_peek(TSQueue *cq);

TSQItem *ts_queue_deq(TSQueue *cq);
void *ts_queue_deq_data(TSQueue *cq);
void ts_queue_enq(TSQueue *cq, TSQItem *item);
int ts_queue_enq_data(TSQueue *cq, void *data);

unsigned ts_queue_count(TSQueue *cq);
BOOL ts_queue_is_empty(TSQueue *cq);

#ifdef __cplusplus
}
#endif

#endif
(4)tsqueue.c:
#include <stdlib.h>
#include <pthread.h>
#include "tsqueue.h"

#define ITEMS_PER_ALLOC 32

TSQueue *ts_queue_create(){
    TSQueue *cq = (TSQueue *) malloc(sizeof(TSQueue));
    ts_queue_init(cq);
    return cq;
}

void ts_queue_destroy(TSQueue *cq){
    if(!cq)
        return;
    pthread_mutex_destroy(&cq->lock);
    pthread_mutex_destroy(&cq->cqi_freelist_lock);
    free(cq);
}

void ts_queue_init(TSQueue *cq){
    if(!cq)
        return;
    pthread_mutex_init(&cq->lock, NULL);
    cq->head = NULL;
    cq->tail = NULL;
    cq->cqi_freelist = NULL;
    pthread_mutex_init(&cq->cqi_freelist_lock, NULL);
    cq->count = 0;
}

TSQItem *ts_queue_item_new(TSQueue *cq) {
    TSQItem *item = NULL;
    if(!cq)
        return NULL;
    pthread_mutex_lock(&cq->cqi_freelist_lock);
    if (cq->cqi_freelist) {
        item = cq->cqi_freelist;
        cq->cqi_freelist = item->next;
    }
    pthread_mutex_unlock(&cq->cqi_freelist_lock);

    if (NULL == item) {
        int i;
        item = (TSQItem *) malloc(sizeof(TSQItem) * ITEMS_PER_ALLOC);
        if (NULL == item){
            //perror("error to malloc cq item");
            return NULL;
        }
        for (i = 2; i < ITEMS_PER_ALLOC; i++)
            item[i - 1].next = &item[i];

        pthread_mutex_lock(&cq->cqi_freelist_lock);
        item[ITEMS_PER_ALLOC - 1].next = cq->cqi_freelist;
        cq->cqi_freelist = &item[1];
        pthread_mutex_unlock(&cq->cqi_freelist_lock);
    }

    return item;
}

void ts_queue_item_free(TSQueue *cq, TSQItem *item){
    if(!cq || !item)
        return;
    pthread_mutex_lock(&cq->cqi_freelist_lock);
    item->next = cq->cqi_freelist;
    cq->cqi_freelist = item;
    pthread_mutex_unlock(&cq->cqi_freelist_lock);
}

TSQItem *ts_queue_head(TSQueue *cq){
    TSQItem *item;
    if(!cq)
        return NULL;
    return cq->head;
}

TSQItem *ts_queue_tail(TSQueue *cq){
    TSQItem *item;
    if(!cq)
        return NULL;
    return cq->tail;
}

TSQItem *ts_queue_peek(TSQueue *cq){
    return ts_queue_head(cq);
}

TSQItem *ts_queue_deq(TSQueue *cq){
    TSQItem *item;
    if(!cq)
        return NULL;

    pthread_mutex_lock(&cq->lock);
    item = cq->head;
    if(NULL != item){
        cq->head = item->next;
        if(NULL == cq->head)
            cq->tail = NULL;
        cq->count--;
    }
    pthread_mutex_unlock(&cq->lock);

    return item;
}

void *ts_queue_deq_data(TSQueue *cq){
    void *data;
    TSQItem *item;
    if(!cq)
        return NULL;
    item = ts_queue_deq(cq);
    if(!item){
        //
        return NULL;
    }
    data = item->data;
    ts_queue_item_free(cq, item);
    return data;
}

void ts_queue_enq(TSQueue *cq, TSQItem *item) {
    if(!cq || !item)
        return;
    item->next = NULL;
    pthread_mutex_lock(&cq->lock);
    if (NULL == cq->tail)
        cq->head = item;
    else
        cq->tail->next = item;
    cq->tail = item;
    cq->count++;
    pthread_mutex_unlock(&cq->lock);
}

int ts_queue_enq_data(TSQueue *cq, void *data){
    TSQItem *item;
    if(!cq || !data)
        return -1;
    item = ts_queue_item_new(cq);
    if(!item){
        //perror("ts_queue_push_data");
        return -1;
    }
    item->data = data;
    ts_queue_enq(cq, item);
    return 0;
}

unsigned ts_queue_count(TSQueue *cq){
    return cq->count;
}

BOOL ts_queue_is_empty(TSQueue *cq){
    return cq->count? TRUE : FALSE;
}
(5)tp_test.c:
#define __DEBUG__

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "thread_pool.h"

#define THD_NUM 10

static pthread_mutex_t lock;
static unsigned exit_cnt;
TpThreadPool *pTp;

void proc_fun(void *arg)
{
    int i;
    int idx = (int)arg;
    printf("=========================%d\n", idx);
    i = 1000000.0 + (int)(9000000.0 * rand() / RAND_MAX);
    fprintf(stderr, "Begin: job %d, sleep %d us\n", idx, i);
    usleep(i);
    fprintf(stderr, "End:   job %d\n", idx);
    pthread_mutex_lock(&lock);
    exit_cnt++;
    pthread_mutex_unlock(&lock);
    if(exit_cnt == THD_NUM)
        tp_exit(pTp);
}

int main(int argc, char **argv)
{
    pTp= tp_create(10, THD_NUM);
    int i;

    exit_cnt = 0;
    pthread_mutex_init(&lock, NULL);
    tp_init(pTp);
    srand((int)time(0));
    for(i=0; i < THD_NUM; i++){
        tp_process_job(pTp, proc_fun, i);
    }
    tp_run(pTp);
    free(pTp);
    fprintf(stderr, "All jobs done!\n");
    return 0;
}
(6)makefile:
SRCS=$(wildcard *.c)
OBJS=$(SRCS:.c=.o)
CC=gcc
INCLUDES=-I./
LIBS=-L./ -lpthread
CCFLAGS = -g -Wall -O0
threadpool : $(OBJS)
	$(CC) $^ -o $@ $(INCLUDES) $(LIBS)

%.o : %.cpp
	$(CC) -c $< $(CCFLAGS)

.PHONY:clean
clean:
	rm -f *.o
ok:
	./threadpool
(7)运行

三、总结

(1)an simple thread pool for linux源码下载:http://sourceforge.net/projects/thd-pool-linux/
(2)查阅网上文章:http://blog.chinaunix.net/uid-18757596-id-1744686.htmlhttp://blog.csdn.net/hinyunsin/article/details/6650879/

(3)若有建议,请留言,在此先感谢!

  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值