线程池实现

线程池的作用

线程池最主要的作用是对于任务处理的异步解耦。

比较耗时的任务,比如日志、数据库操作,可以扔到线程池去处理,不影响主线程的性能。

关于CPU和线程的亲缘性绑定:

主要注重CPU处理能力的话,可以进行CPU的亲缘性绑定;重在异步解耦,没必要将线程和CPU绑定。

线程池的原理

线程池中的角色

线程池中包含3种角色:

  1. worker,即工作线程,一个worker对应一个线程。包含线程id和线程结束标志。
  2. job,即任务,包含任务执行方法和参数。
  3. thread_pool, 对worker和job进行管理,分别包含一个worker队列和一个job队列。

线程池与连接池不一样,线程之间是一种争夺式的关系。线程的核心工作就是取任务,执行。

外界只需要往任务队列里面抛任务就可以了。

线程入口函数,里面有一个while的循环,不断从任务队列里面取任务,调用任务的回调函数去执行。

任务队列是线程池里面所有线程都可以访问的临界资源,A线程能从队列中取任务,B线程也可以取任务。

typedef struct _worker {

    pthread_t id;
    int terminate;

    struct _thread_pool *pool;

    struct _worker *prev;
    struct _worker *next;

} worker_t;


typedef struct _job {

    void (*job_func)(void *arg);
    void *user_data;

    struct _job *prev;
    struct _job *next;

} job_t;


typedef struct _thread_pool {

    worker_t *workers;
    job_t *jobs;

    pthread_cond_t cond;
    pthread_mutex_t mtx;

} thread_pool_t;

线程池接口

必要的3个接口:

  1. thread_pool_create(), 创建线程池
  2. thread_pool_destroy(), 销毁线程池
  3. thread_pool_push_job(), 往线程池里面放任务。

其他的接口,比如获取任务数量,空闲线程数量,可以作为扩展,用来动态的增加/减少线程数量。

int thread_pool_create(thread_pool_t *pool, int thread_num);
int thread_pool_destroy(thread_pool_t *pool);
int thread_pool_push_job(thread_pool_t *pool, job_t *job)

手写一个线程池

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

#include <pthread.h>



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

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



typedef struct _worker {

    pthread_t id;
    int terminate;

    struct _thread_pool *pool;

    struct _worker *prev;
    struct _worker *next;

} worker_t;


typedef struct _job {

    void (*job_func)(void *arg);
    void *user_data;

    struct _job *prev;
    struct _job *next;

} job_t;


typedef struct _thread_pool {

    worker_t *workers;
    job_t *jobs;

    pthread_cond_t cond;
    pthread_mutex_t mtx;

} thread_pool_t;

void * thread_callback(void *arg) {

    worker_t *worker = (worker_t *)arg;

    while (1) {

        pthread_mutex_lock(&worker->pool->mtx);
        while (worker->pool->jobs == NULL) {
            if (worker->terminate) break;
            pthread_cond_wait(&worker->pool->cond, &worker->pool->mtx);
        }

        if (worker->terminate) {
            pthread_mutex_unlock(&worker->pool->mtx);
            break;
        }


        job_t *job = worker->pool->jobs;
        LL_REMOVE(job, worker->pool->jobs);

        pthread_mutex_unlock(&worker->pool->mtx);

        if (job == NULL) continue;

        job->job_func(job);
    }

    free(worker);
}


int thread_pool_create(thread_pool_t *pool, int thread_num) {

    if (pool == NULL) return -1;
    if (thread_num < 1) thread_num = 1;

    memset(pool, 0, sizeof(thread_pool_t));
    pool->cond = (pthread_cond_t)PTHREAD_COND_INITIALIZER;
    pool->mtx = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;


    int idx = 0;
    for (idx = 0; idx < thread_num; idx++) {

        worker_t *worker = (worker_t *)malloc(sizeof(worker_t));
        if (worker == NULL) {
            perror("malloc");
            return idx;
        }

        memset(worker, 0, sizeof(worker_t));
        
        worker->pool = pool;

        int ret = pthread_create(&worker->id, NULL, thread_callback, worker);
        if (ret) {
            perror("pthread_create");
            free(worker);
            return idx;
        }

    }

    return idx;

}

int thread_pool_destroy(thread_pool_t *pool) {

    if (pool == NULL) return -1;

    worker_t *worker = NULL;

    for (worker = pool->workers; worker != NULL; worker = worker->next) {
        worker->terminate = 1;
    }

    pthread_mutex_lock(&pool->mtx);
    pthread_cond_broadcast(&pool->cond);
    pthread_mutex_unlock(&pool->mtx);

    return 0;
}

int thread_pool_push_job(thread_pool_t *pool, job_t *job) {

    if (pool == NULL || job == NULL) return -1;

    pthread_mutex_lock(&pool->mtx);
    LL_ADD(job, pool->jobs);
    pthread_cond_signal(&pool->cond);
    pthread_mutex_unlock(&pool->mtx);

    return 0;
}


#if 1


void count(void *arg) {

    job_t *job = (job_t *)arg;

    int idx = *(int *)job->user_data;
    printf("idx = %d, thread_id = %lu\n", idx, pthread_self());

    free(job->user_data);
    free(job);

}

int main() {

    thread_pool_t pool = {0};
    const int thread_num = 20;

    thread_pool_create(&pool, thread_num);

    const int task_num = 1000;
    int i = 0;
    for (i = 0; i < task_num; i++) {

        job_t *job = malloc(sizeof(job_t));
        if (job == NULL) exit(1);
        memset(job, 0, sizeof(job_t));

        job->job_func = count;
        job->user_data = malloc(sizeof(int));
        if (job->user_data == NULL) exit(1);
        *(int *)job->user_data = i;

        thread_pool_push_job(&pool, job);

    }

    getchar();

    thread_pool_destroy(&pool);
    sleep(3);

}


#endif

nginx线程池

nginx里面的线程池跟我们上面的线程池代码类似,也是三个主要接口

static ngx_int_t ngx_thread_pool_init(ngx_thread_pool_t *tp, ngx_log_t *log, ngx_pool_t *pool);
static void ngx_thread_pool_destroy(ngx_thread_pool_t *tp);
ngx_int_t ngx_thread_task_post(ngx_thread_pool_t *tp, ngx_thread_task_t *task);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值