C实现一个简易线程池

36 阅读5分钟

线程池的实现

线程池的组成

  • N个线程
  • 一个任务队列

工作原理

  • 避免线程创建销毁切换带来的开销,多个线程同时存在,在有新任务到来的情况下,线程根据当前所处状态去竞争待处理的任务资源,成功获取到任务之后执行并返回,再重新进入等待新任务到来的状态

实现思路

  • 线程池创建时,同时创建N个线程
  • 线程池对象内部实现一个任务队列,用于保存待执行的任务对象
  • 外部线程可以调用开放接口添加待处理任务
  • 开放接口还包括线程池的创建和销毁

线程池中类型定义

// 工作线程中节点定义
typedef struct  _worker    
{
    pthread_t pthread_id;    // 线程ID
    int terminated;       // 是否终止的标志

    struct _threadpool *pool;   // 与池对象绑定

    struct _worker *prev;   // 链表结构
    struct _worker *next;
}WORKER;

// 任务队列中节点定义
typedef struct _job           // 任务队列的节点
{
    void (*func)(struct _job *arg);        // 方便在job执行完之后直接释放该job对象

    void *user_data;   // 执行所需要的参数

    struct _job *next;  // 链表结构
    struct _job *prev;
}JOB;

// 定义线程池对象类型
typedef struct _threadpool
{
    WORKER *workers;        // 工作线程
    JOB *jobs;              // 任务队列

    pthread_cond_t cond;    // 条件变量
    pthread_mutex_t mutex; // 互斥锁,与条件变量配合使用
}THREADPOOL;

//链表的增删操作使用宏定义实现

#define ADD_ITEM(item, list) do{            \
    item->prev = NULL;                      \
    item->next = list;                      \
    if(list != NULL) list->prev = item;     \
    list = item;                            \
    } while (0);

#define DEL_ITEM(item, list) do{                            \
    if(list->prev != NULL) list->prev->next = item->next;   \
    if(list->next != NULL) list->next->prev = item->prev;   \
    if(item == list) list = item->next;                     \
    item->prev = NULL;                                      \
    item->next = NULL;                                      \
    } while (0);
   

创建一个线程池

// 工作线程的调用对象
void *threadCallback(void *arg)
{
    WORKER *worker = (WORKER *)arg;

    while(1)
    {
        pthread_mutex_lock(&worker->pool->mutex);

        while(worker->pool->jobs == NULL)
        {
            pthread_cond_wait(&worker->pool->cond, &worker->pool->mutex);       // 等待唤醒
        }

        // 判断是否需要退出当前线程
        if(worker->terminated)
        {
            pthread_mutex_unlock(&worker->pool->mutex);
            break;
        }
        
         // wait返回,说明此时当前池子中的任务队列中有任务待执行
         // 从头部取出
         JOB *job = worker->pool->jobs;
         if(job)
            DEL_ITEM(job, worker->pool->jobs);
            
        // 互斥资源操作结束及时解锁,减小锁粒度
        pthread_mutex_unlock(&worker->pool->mutex);

        if(job == NULL) continue;

        // 执行任务
        job->func(job);
    }

    // 释放当前线程中创建的worker
    free(worker);
    worker = NULL;
}

// 创建线程池
int thread_pool_create(THREADPOOL *pool, int threadNum)
{
    if(pool == NULL)    return 0;

    if(threadNum < 1) threadNum = 1;

    pthread_cond_init(&pool->cond, NULL);
    pthread_mutex_init(&pool->mutex, NULL);

    // 分配多个工作线程的对象
    int idx = 0;
    for(idx = 0; idx < threadNum; idx++)
    {
        WORKER *worker = (WORKER *) malloc(sizeof(WORKER));
        if(worker == NULL)
        {
            perror("worker allocation failed\n");
            return idx;
        }
        memset(worker, 0, sizeof(WORKER));
        
        int ret = pthread_create(&worker->pthread_id, NULL, threadCallback, worker);
        if(ret)
        {
            perror("pthread_create failed\n");
            free(worker);
            worker = NULL;
            return idx;
        }

        worker->pool = pool;            // 工作线程通过池对象访问该池中的任务队列
        ADD_ITEM(worker, pool->workers);
    }
    return idx;
}

销毁一个线程池

void thread_pool_destroy(THREADPOOL* pool)
{
    WORKER* worker = NULL;
    for(worker = pool->workers; worker != NULL; worker = worker->next)
    {
        worker->terminated = 1;
    }

    // 唤醒所有阻塞的线程,线程退出时顺带销毁当前worker
    pthread_mutex_lock(&worker->pool->mutex);
    pthread_cond_broadcast(&worker->pool->cond);
    pthread_mutex_unlock(&worker->pool->mutex);
}

添加任务

int thread_pool_push_task(THREADPOOL *pool, JOB *job)
{
    if(job == NULL) return 0;

    pthread_mutex_lock(&pool->mutex);

    ADD_ITEM(job, pool->jobs);
   
    pthread_mutex_unlock(&pool->mutex);
    
    // 唤醒一个线程
    pthread_cond_signal(&pool->cond);   
}

测试代码

#define POOL_MAX_ 50
#define TASK_MAX_ 1000

void jobFunc(JOB *job)
{
    int value = *(int *)job->user_data;
    printf("value : %d , selfid : %lu \n", value, pthread_self());

    // job分配的空间再使用后自行释放
    free(job);
    job = NULL;
}

void main(int argc, char *argv[])
{
    THREADPOOL pool = {0};
    int ret = thread_pool_create(&pool, POOL_MAX_);
    if(ret != POOL_MAX_)
    {
        perror("pool_create failed\n");
        return;
    }

    for(int i = 0; i < TASK_MAX_; i++)
    {
        JOB *job = (JOB *)malloc(sizeof(JOB));
        job->func = jobFunc;
        job->user_data = malloc(sizeof(int));
        *(int *)job->user_data = i;

        thread_pool_push_task(&pool, job);
    }

    getchar();

}

测试效果

终端输出以下内容
value : 134 , selfid : 140526279378496
value : 133 , selfid : 140526287771200
value : 132 , selfid : 140526270985792
value : 131 , selfid : 140526254200384
value : 402 , selfid : 140526245807680
value : 556 , selfid : 140526237414976
value : 658 , selfid : 140526262593088
value : 812 , selfid : 140526229022272
value : 863 , selfid : 140526220629568
value : 862 , selfid : 140526212236864
value : 861 , selfid : 140526195451456
value : 999 , selfid : 140526187058752
value : 998 , selfid : 140526203844160
value : 997 , selfid : 140526170273344
value : 996 , selfid : 140526178666048
value : 995 , selfid : 140526161880640
value : 994 , selfid : 140526153487936
value : 993 , selfid : 140526145095232
value : 992 , selfid : 140526128309824
value : 991 , selfid : 140526119917120
value : 989 , selfid : 140526136702528
value : 988 , selfid : 140526103131712
value : 987 , selfid : 140526094739008
value : 986 , selfid : 140526086346304
value : 985 , selfid : 140526077953600
value : 984 , selfid : 140526061168192
value : 983 , selfid : 140526052775488
value : 982 , selfid : 140526069560896
value : 981 , selfid : 140526035990080
value : 980 , selfid : 140526044382784
value : 979 , selfid : 140526027597376
value : 978 , selfid : 140526010811968
value : 977 , selfid : 140526002419264
value : 976 , selfid : 140525994026560
value : 975 , selfid : 140526019204672
value : 974 , selfid : 140525985633856
value : 973 , selfid : 140525977241152
value : 972 , selfid : 140525943670336
value : 971 , selfid : 140525918492224
value : 136 , selfid : 140526296163904
value : 968 , selfid : 140525910099520
...