线程池(2)

common.h


#ifndef _COMMON_H_
#define _COMMON_H_

#define OK                        0
#define ERROR                        -1

#endif
log.h


#ifndef _LOG_H_
#define _LOG_H_

#undef dump                                                                                                                  
#define dump(y,x...) do {} while(0)

#endif
queue.h


ifndef _QUEUE_H_
#define _QUEUE_H_

#define QUEUE_SIZE 2000

typedef void (*fp) (void *);
//初始化队列
void* q_init(size_t size, void *pool);

int q_add(void *q, void *func, void *arg);

void q_print(void *q, fp p);

void print_pointer(void *data);

void q_drop(void *q);

int q_isempty(void *q);

#endif 
queue.c


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>

#include "common.h"
#include "threadpool.h"
#include "utils.h"
#include "log.h"
#include "queue.h"

//队列节点数据结构
typedef struct _Queue_node{
    void    *func;
    void    *arg;
} Q_node;

//队列结构
typedef struct _Queue{
    Q_node         *first;
    Q_node         *last;
    size_t        size;
    Q_node        *head;
    void        *pool;
    pthread_mutex_t mutex;
    pthread_cond_t  has_data_cond;
    pthread_cond_t    drop_cond;
    char        is_close;
    pthread_t    tid;
} Q_t;

void    q_remove(Q_t *q, void** func, void** arg);
int        q_isfull(Q_t *q);
void*    q_thread(void *q);
void    print_p(void *data);
int        q_length(Q_t *q);

void* q_init(size_t size, void *pool)
{
    ASSERT(size > 0);
    ASSERT(pool);

    Q_t *q = (Q_t*)malloc(sizeof(Q_t));
    if (NULL == q) return NULL;

    Q_node *qn = (Q_node*)malloc(size * sizeof(Q_node));

    if (NULL == qn) return NULL;
    q->first = qn;
    q->last = qn;
    q->head = qn;
    q->size = size;
    q->pool = pool;
    q->is_close = 0;
    memset(q->head, 0, size * sizeof(Q_node));

    pthread_mutex_init(&q->mutex, NULL);
    pthread_cond_init(&q->has_data_cond, NULL);
    pthread_cond_init(&q->drop_cond, NULL);

    if (0 != pthread_create(&q->tid, NULL, q_thread, q)) {
        free(q->head);
        q->head = NULL;
        free(q);
        q = NULL;
        dump(L_ERROR, "Create thread q_thread error");
    }

    return (void*)q;
}

int q_add(void *qt, void *func, void *arg)
{
        ASSERT(qt);
        ASSERT(func);
    /*arg possible NULL*/

    Q_t *q = (Q_t*)qt;

    pthread_mutex_lock(&q->mutex);
    if (OK == q_isfull(q)) {
        pthread_mutex_unlock(&q->mutex);    
        return ERROR;
    }
    ASSERT(q->last->func == NULL);

    q->last->func = func;
    q->last->arg = arg;
    q->last++;

    if (q->last == q->first + 1) {
            ASSERT(1 == q_length(q));
            dump(L_DEBUG, "Queue send signal, has data");
            pthread_cond_signal(&q->has_data_cond);
    }

    if (q->last == q->head + q->size)
            q->last = q->head;
    dump(L_DEBUG, "Add Queue Length %d", q_length(q));
    pthread_mutex_unlock(&q->mutex);

    return OK;
}

int q_isempty(void *qt)
{
    Q_t *q = qt;
    ASSERT(q);
    if (q->last == q->first) {
            if (NULL == q->first->func) {
                    dump(L_INFO, "Queue is empty");
                    return OK;
            } 
    }
    return ERROR;
}

int q_isfull(Q_t *q)
{
    ASSERT(q);
    if (q->last == q->first) {
            if (NULL != q->last->func) {
                    dump(L_INFO, "Queue is full");
                    return OK;
            }
    }
    return ERROR;
}

void* q_thread(void *qt)
{
    ASSERT(qt);
    Q_t *q = qt;
    void *func;
    void *arg;
    while(0 == q->is_close) {
            pthread_mutex_lock(&q->mutex);
            if (OK == q_isempty(q)) {
            pthread_cond_wait(&q->has_data_cond, &q->mutex);
        }
        /* possible close signal has_data cond */
        if (0 != q->is_close) {
                    pthread_mutex_unlock(&q->mutex);
            break;
        }
        q_remove(q, &func, &arg);
                pthread_mutex_unlock(&q->mutex);
        tp_add(q->pool, func, arg); //unlock first then tp add, let q_add go 
    }
    tp_drop(q->pool);
    q->pool = NULL;
    pthread_mutex_lock(&q->mutex);
    pthread_cond_signal(&q->drop_cond);
    pthread_mutex_unlock(&q->mutex);
    pthread_exit(NULL);
    return NULL;
}

void q_remove(Q_t *q, void** func, void** arg)
{
    ASSERT(q);
    ASSERT(q->first->func); 
    ASSERT(func);
    ASSERT(arg);

    *func = q->first->func;
    *arg = q->first->arg;
    q->first->func = NULL;
    q->first->arg = NULL;
    q->first++;

    if (q->first == q->head + q->size)
        q->first = q->head;
    dump(L_DEBUG, "Remove Queue Length %d", q_length(q));
    //q_print(q, print_p);
}

void q_drop(void *qt)
{
    ASSERT(qt);

    Q_t* q = (Q_t*)qt;
    pthread_mutex_lock(&q->mutex);

    q->is_close = 1;
    /* let q thread not wait */
          if (OK == q_isempty(q))
        pthread_cond_signal(&q->has_data_cond);    
    pthread_cond_wait(&q->drop_cond, &q->mutex);

    pthread_join(q->tid, NULL);

    pthread_mutex_unlock(&q->mutex);

    pthread_mutex_destroy(&q->mutex);
    pthread_cond_destroy(&q->has_data_cond);
    pthread_cond_destroy(&q->drop_cond);
    free(q->head);
    q->head = NULL;
    free(q);
}

int q_length(Q_t *q)
{
    ASSERT(q);

    if (q->last < q->first) {
        return q->size - (q->first - q->last);
    } else {
        return q->last - q->first;
    }
}
void q_print(void *qt, fp p)
{
    ASSERT(qt);
    ASSERT(p);
    Q_t *q = qt;    
    Q_node* qn;
    int i;

    for (i = 0, qn = q->head; i < q->size; i++, qn++) {
        p(qn->func);
        //p(qn->arg);
    }
}

void print_p(void* data)
{
    if (NULL == data)
        printf("[ ]");
    else 
        printf("[x]");
}

/*
int main()
{
    void* d;
    Q_t *q = q_init(10,NULL);
    int z1 = 1;
    int z2 = 2;
    int z3 = 3;
    q_add(q, &z1, NULL);
    q_add(q, &z2, NULL);
    q_add(q, &z3, NULL);

        q_print(q, stdout);

    return 1;
} 
*/
util.h



#ifndef _UTILS_H_
#define _UTILS_H_

#ifdef DEBUG
#define ASSERT(f) do {if(f) ((void)0); else _Assert(#f, __FILE__, __LINE__);} while(0)
#else
#define ASSERT(f) ((void)0)
#endif

#include <sys/time.h>

void    _Assert(char*, char*, unsigned);


#endif
util.c


#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <time.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <net/if.h>

#include "common.h"
#include "utils.h"
#include "log.h"

void _Assert (char* name, char* strFile, unsigned uLine)
{
    dump(L_ERROR, "Assertion failed: %s, %s, line %u", name, strFile, uLine);
    abort();
}
threadpool.h

#ifndef _THREADPOOL_
#define _THREADPOOL_

#define MAX_POOL    200
#define INIT_POOL    20
#define STACKSIZE    1048576

typedef void (*func_pointer) (void *);

void*    tp_init(int max, int init);

int    tp_add(void *pool, func_pointer fp, void *arg);

void*    tp_drop(void *pool);

void    tv_sub(struct timeval *out, const struct timeval *in);

#endif
threadpool.c



#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/select.h>

#include "threadpool.h"
#include "log.h"
#include "utils.h"

typedef struct _Thread
{
    pthread_t    id;
    pthread_mutex_t mutex;
    pthread_cond_t    cond;
    func_pointer    func;
    void         *arg;
    void            *parent;
} Thread_t;

typedef struct _Threadpool_t
{
    pthread_mutex_t mutex;
    pthread_cond_t  idle_cond;        /*拿到条件 意味着有空线程 可利用        */
    pthread_cond_t    allidle_cond;        /*拿到条件 意味着线程都闲置了          */
    pthread_cond_t  drop_cond;        /*拿到条件 意味着线程都退出了,可删除线程池了    */
    Thread_t    **thread_list;        /*线程数组                */
    int        thread_idle_num;    /*空闲线程个数                */
    int         thread_hwm_num;        /*创建线程的高水位                */
    int        thread_max_num;
    int        is_close;        /*线程池关闭标志 1 是要关闭            */
} Tp_t;

void*    t_thread(void *arg);
int        t_idle(Tp_t *pool, Thread_t *thread);
void    tv_sub(struct timeval *out,const struct timeval *in);
void    init_func(void* arg);

void* tp_init (int max, int init)
{
    int i;
    ASSERT(max > 0);
    ASSERT(init >= 0);
    ASSERT(max >= init);

    Tp_t *pool = NULL;
        
    if (NULL == (pool = (Tp_t*)malloc(sizeof(Tp_t)))) {
        return NULL;
    }
    
    if (NULL == (pool->thread_list = 
        (Thread_t**)malloc(sizeof(Thread_t*) * max))) 
    {
        free(pool);
        pool = NULL;
        return NULL;
    }

    memset(pool->thread_list, 0, sizeof(Thread_t*) * max);

    pthread_mutex_init(&pool->mutex,NULL);
    pthread_cond_init(&pool->idle_cond,NULL);
    pthread_cond_init(&pool->allidle_cond,NULL);    
    pthread_cond_init(&pool->drop_cond,NULL);
    
    pool->thread_idle_num = 0;
    pool->thread_hwm_num = 0;
    pool->is_close    = 0;
    pool->thread_max_num = max;

    dump(L_SUCCESS, "create thread pool %d successfully!!", pool->thread_max_num);

    for (i = 0; i < init; i++) {
        if (-1 == tp_add(pool, init_func, NULL)) {
            free(pool->thread_list);
            pool->thread_list = NULL;
            free(pool);
            pool = NULL;
            return NULL;
        }
    }

    dump(L_SUCCESS, "init thread pool %d/%d successfully!!", 
        pool->thread_hwm_num, pool->thread_max_num);

    return (void *)pool;
}

/* execute job and then idle thread, then cond_wait , if is_close ,then return*/
void* t_thread(void *arg)
{
    if (NULL == arg) return NULL;

    Thread_t *thread =(Thread_t*)arg;
    Tp_t *pool = thread->parent;

    /*
        change while to do while for
        a thread add, then quickly pool drop 
        the thread possible cant execute once
    */
    do {
        struct timeval start_time;
        struct timeval end_time;
        gettimeofday(&start_time,NULL);
        if (thread->func) thread->func(thread->arg);
        gettimeofday(&end_time,NULL);
        tv_sub(&end_time,&start_time);

        pthread_mutex_lock(&thread->mutex);
        if (0 == t_idle(pool,thread)) {
            pthread_cond_wait(&thread->cond,&thread->mutex);
            pthread_mutex_unlock(&thread->mutex);
        } else {
            pthread_mutex_unlock(&thread->mutex);
            pthread_cond_destroy(&thread->cond);
            pthread_mutex_destroy(&thread->mutex);

            free(thread);
            break;
        }
    } while(0 == pool->is_close);

    /* pool is close or thread is exeception idle_thread failure*/
    pthread_mutex_lock(&pool->mutex);
    pool->thread_hwm_num--;
    if (pool->thread_hwm_num <= 0) pthread_cond_signal(&pool->drop_cond);
    pthread_mutex_unlock(&pool->mutex);

    return NULL;
}

/*let this thread idle ,can be use */
int t_idle(Tp_t *pool,Thread_t *thread)
{
    pthread_mutex_lock(&pool->mutex);
    pool->thread_list[pool->thread_idle_num] = thread;    /*空闲的线程指针放回来*/
    pool->thread_idle_num++;                /*假设有释放后有5个线程,修改的是thread_list[4]*/    

    dump(L_DEBUG, "One Thread is idle %d %lu", pool->thread_idle_num, pthread_self());
    
    pthread_cond_signal(&pool->idle_cond);            /*这个线程可用了,告诉有线程空闲,解决线程不足的等待*/

    if (pool->thread_idle_num >= pool->thread_hwm_num)    /*如果所有线程都idle*/
        pthread_cond_signal(&pool->allidle_cond);
    
    pthread_mutex_unlock(&pool->mutex);

    return 0;
}

/*往线程池里加任务,参数为任务要执行的函数和参数*/

int tp_add(void *_pool,func_pointer fp,void *arg)
{
    //arg can be NULL
    if ((NULL == _pool)||(NULL == fp)) {
        return -1;
    }

    Tp_t        *pool    = (Tp_t*)_pool;
    Thread_t    *thread    = NULL;            /*可用线程*/

    pthread_mutex_lock(&pool->mutex);

    if (pool->thread_idle_num <= 0) {
        /*无空闲线程*/
        if (pool->thread_hwm_num >= pool->thread_max_num) {
            /*无法再创建线程了,到达上限了,只能等待到有空闲线程*/
            dump(L_FAILURE,"Idle thread is none, begin hang...");
            pthread_cond_wait(&pool->idle_cond,&pool->mutex);
        } else {
            pthread_attr_t    attr;
            /*创建线程*/
            if (NULL == (thread = (Thread_t*)malloc(sizeof(Thread_t))))
            {
                dump(L_FAILURE,"error-----\n");
                pthread_mutex_unlock(&pool->mutex);                
                return -1;
            }
            memset(thread,0,sizeof(Thread_t));
            pthread_mutex_init(&thread->mutex,NULL);
            pthread_cond_init(&thread->cond,NULL);
            thread->func = fp;
            thread->arg  = arg;
            thread->parent = pool;

            pthread_attr_init(&attr);
            pthread_attr_setstacksize (&attr, STACKSIZE);

            pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);

            if (0 == pthread_create(&thread->id,&attr,t_thread,thread))
            {
                pool->thread_hwm_num++;
                dump(L_DEBUG, "Create thread successfully %d-%d",
                    pool->thread_hwm_num, pool->thread_max_num);
                pthread_attr_destroy(&attr);
                pthread_mutex_unlock(&pool->mutex);
                return 0;    
                /* 这里idle不会增加,只有在idle_thread + 1 */
            } else {
                pthread_mutex_destroy(&thread->mutex);
                pthread_cond_destroy(&thread->cond);
                pthread_attr_destroy(&attr);
                free(thread);
                pthread_mutex_unlock(&pool->mutex);
                return -1;
            }
        }
    }

    /*有空闲线程 1 本来就有 2 等了一会有的*/
    /*选择最上面的一个可用线程*/

    pool->thread_idle_num--;                /*假设有5个空闲线程,那么能使用的就是thread_list[4]*/
    thread = pool->thread_list[pool->thread_idle_num];
    pool->thread_list[pool->thread_idle_num] = NULL;    /*取出后,清空,因为不一定放回这个位置*/        

    pthread_mutex_lock(&thread->mutex);    
    thread->func = fp;
    thread->arg = arg;
    thread->parent = pool;

    pthread_cond_signal(&thread->cond);            /*通知该线程,开始干活*/
    pthread_mutex_unlock(&thread->mutex);

    dump(L_SUCCESS,"pool state : idle thread %d allocate thread %d",
        pool->thread_idle_num, pool->thread_hwm_num);
    pthread_mutex_unlock(&pool->mutex);

    return 0;
}

/* drop thread pool*/
void* tp_drop(void *_pool)
{
    if (NULL == _pool) {
        dump(L_FAILURE,"drop threadpool error\n");
        return NULL;
    }

    int        i;
    Tp_t        *pool = (Tp_t *)_pool;
    Thread_t    *thread    = NULL;
    pthread_mutex_lock(&pool->mutex);

    pool->is_close = 1;

    /*wait all thread idle, only idle then signal*/
    if (pool->thread_hwm_num > pool->thread_idle_num) {
        dump(L_SUCCESS,"Wait %d thread idle", 
            pool->thread_hwm_num - pool->thread_idle_num);
        pthread_cond_wait(&pool->allidle_cond, &pool->mutex);
    }
    ASSERT(pool->thread_hwm_num == pool->thread_idle_num);
    
    /* signal all thread, let thread exit */
    for(i = 0; i<pool->thread_hwm_num; i++) {
        thread = pool->thread_list[i];
        pthread_mutex_lock(&thread->mutex);
        pthread_cond_signal(&thread->cond);
        pthread_mutex_unlock(&thread->mutex);
    }
    /* some thread not exit */
    if (pool->thread_hwm_num > 0) {
        dump(L_SUCCESS,"Wait %d thread empty", pool->thread_hwm_num);
        pthread_cond_wait(&pool->drop_cond, &pool->mutex);
    }

    /* now all thread exit */
    ASSERT(pool->thread_hwm_num == 0);

    for(i = 0; i < pool->thread_idle_num; i++) {
        free(pool->thread_list[i]);
        pool->thread_list[i] = NULL;
    }

    pthread_mutex_unlock(&pool->mutex);

    pthread_mutex_destroy(&pool->mutex);
    pthread_cond_destroy(&pool->idle_cond);
    pthread_cond_destroy(&pool->allidle_cond);
    pthread_cond_destroy(&pool->drop_cond);

    free(pool->thread_list);
    pool->thread_list = NULL;
    free(pool);
    
    return NULL;
}

void tv_sub(struct timeval* out,const struct timeval* in)
{
    /*out->tv_usec < in->tv_usec*/
    if((out->tv_usec -= in->tv_usec) < 0) {
        /*negative -> postive 1,000,000 = 1s*/            
        (out->tv_sec)--;
        out->tv_usec+=1000000;
    }
    out->tv_sec-=in->tv_sec;
}

/* only use init thread */
void init_func(void* arg)
{
    sleep(2);
}
test.c




#include <stdio.h>
#include <unistd.h>
#include <sys/select.h>

#include "common.h"
#include "threadpool.h"
#include "queue.h"
#include "log.h"

#define  DEBUG  1
void f1(void *arg) {
    printf("call f1\n");
    sleep(1);    
}

void f2(void *arg) {
    printf("call f2\n");
    sleep(3);
}

void  f3(void *arg)
{
        printf("call f3\n");
        sleep(2);
}

int main() 
{
    void *pool = NULL;
    void *q = NULL;

    if (NULL == (pool = tp_init(MAX_POOL, INIT_POOL))) {
        printf("tp_init error");
        return ERROR;
    }
               
        if (NULL == (q = q_init(QUEUE_SIZE, pool))) {
        printf("q_init error");
        return ERROR;    
    }

    int i = 0;
    for (i = 0; i < 20; i++) {
        q_add(q, f1, NULL);
        q_add(q, f2, NULL); 
        q_add(q, f3, NULL);
    }

        while(OK != q_isempty(q)) {
        sleep(0.1);
    }

    q_drop(q);

    return OK;
}
posted @ 2012-10-22 13:37  风去无痕  阅读(195)  评论(0编辑  收藏  举报