C语言实现一个线程池

一、为什么要线程池?
  1. 某类任务特别耗时,严重影响该线程处理其他任务。
  2. 在其它线程异步执行该任务。
  3. 线程资源的开销与cpu核心之间平衡选择
  4. 作用
    ①复用线程资源
    ②充分利用系统资源
    ③异步执行耗时任务
二、线程池
  • 线程池是一个生产消费模型
  • 构成
    • 生产者线程 --> 发布任务
    • 线程池(消费者)
      • 线程
        • 取出任务
        • 执行任务
        • 线程调度
          • mutex+condition
          • 从无到有
          • 从有到无
    • 队列
      • 任务
        • 任务的上下文
        • 任务执行函数
    • 平衡选择
      • 耗时任务
        • io密集
          • 2 * n (核心数) + 2
        • cpu密集
          • 核心数 n
        • 确定线程池线程
          • (io等待时间 + cpu运算时间)* 核心数 / cpu运算时间
三、实现一个线程池
  1. 接口设计
    1. 创建线程池的接口
      1. 线程池的数量
      2. 队列的长度
    2. 销毁线程池的接口
      1. 标记线程池退出
      2. 通知所有线程
    3. 生产者抛出任务的接口
      1. 构造任务
      2. 放入队列
      3. 通知线程唤醒
  2. 线程池结构体图
  3. 代码
    1. main.c
    2. thrd_pool.c
    3. thrd_pool.h

线程池结构体图

在这里插入图片描述

main.c

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include "thrd_pool.h"
int nums = 0;
int done = 0;
pthread_mutex_t lock;
void do_task(void *arg) {
    usleep(10000);
    pthread_mutex_lock(&lock);
    done++;
    printf("doing %d task\n", done);
    pthread_mutex_unlock(&lock);
}
int main(int argc, char **argv) {
    int threads = 8;
    int queue_size = 256;
    if (argc == 2) {
        threads = atoi(argv[1]);
        if (threads <= 0) {
            printf("threads number error: %d\n", threads);
            return 1;
        }
    } else if (argc > 2) {
        threads = atoi(argv[1]);
        queue_size = atoi(argv[2]);
        if (threads <= 0 || queue_size <= 0) {
            printf("threads number or queue size error: %d,%d\n", threads, queue_size);
            return 1;
        }
    }
    thread_pool_t *pool = thread_pool_create(threads, queue_size);
    if (pool == NULL) {
        printf("thread pool create error!\n");
        return 1;
    }
    sleep(100);
    while (thread_pool_post(pool, &do_task, NULL) == 0) {
        pthread_mutex_lock(&lock);
        nums++;
        pthread_mutex_unlock(&lock);
    }
    printf("add %d tasks\n", nums);
   
    wait_all_done(pool);
    printf("did %d tasks\n", done);
    thread_pool_destroy(pool);
    return 0;
}

thrd_pool.h


#ifndef _THREAD_POOL_H
#define _THREAD_POOL_H
typedef struct thread_pool_t thread_pool_t;
typedef void (*handler_pt) (void *);
thread_pool_t *thread_pool_create(int thrd_count, int queue_size);  
int thread_pool_post(thread_pool_t *pool, handler_pt func, void *arg);
int thread_pool_destroy(thread_pool_t *pool);
int wait_all_done(thread_pool_t *pool);
#endif


thrd_pool.c


#include <pthread.h>
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include "thrd_pool.h"
typedef struct task_t {
    handler_pt func;
    void * arg;
} task_t;
typedef struct task_queue_t {
    uint32_t head;
    uint32_t tail;
    uint32_t count;
    task_t *queue;
} task_queue_t;
struct thread_pool_t {
    pthread_mutex_t mutex;
    pthread_cond_t condition;
    pthread_t *threads;
    task_queue_t task_queue;
    int closed;   // ???
    int started; // 当前运行的线程数
    int thrd_count;
    int queue_size;
    int a;
};
static void * thread_worker(void *thrd_pool);
static void thread_pool_free(thread_pool_t *pool);
thread_pool_t *thread_pool_create(int thrd_count, int queue_size) {
   
    thread_pool_t *pool;  
    if (thrd_count <= 0 || queue_size <= 0) {
        return NULL;
    }
    pool = (thread_pool_t*) malloc(sizeof(thread_pool_t));
    if (pool == NULL) {
        return NULL;
    }
    pool->thrd_count = 0;    // 线程创建之前初始化为 0, 当创建成功时更新
    pool->queue_size = queue_size;
    // 任务加入队列采用尾插法
    pool->task_queue.head = 0;    
    pool->task_queue.tail = 0;
    pool->task_queue.count = 0;
    pool->started = 0;    //
    pool->closed = 0;
    pool->task_queue.queue = (task_t*)malloc(sizeof(task_t)*queue_size);
    if (pool->task_queue.queue == NULL) {
        // TODO: free pool
        return NULL;
    }
    pool->threads = (pthread_t*) malloc(sizeof(pthread_t) * thrd_count);
    if (pool->threads == NULL) {
        // TODO: free pool
        return NULL;
    }
    int i = 0;
    for (; i < thrd_count; i++) {
        if (pthread_create(&(pool->threads[i]), NULL, thread_worker, (void*)pool) != 0) {
            // TODO: free pool
            return NULL;
        }
        pool->thrd_count++;   // 记录线程池初始创建时总线程数
        pool->started++;      // 记录程序运行过程中线程池某时刻存在的线程数
    }
    // 静态初始化, 不需要销毁
    // pool->mutex = PTHREAD_MUTEX_INITIALIZER;  // 初始化互斥锁
    // pool->condition = PTHREAD_COND_INITIALIZER;    // 初始化条件变量
    // 动态初始化, 需要销毁
    pthread_mutex_init(&(pool->mutex), NULL);
    pthread_cond_init(&(pool->condition), NULL);
    return pool;
}
int thread_pool_post(thread_pool_t *pool, handler_pt func, void *arg) {
    if (pool == NULL || func == NULL) {
        return -1;
    }
    task_queue_t *task_queue = &(pool->task_queue);
    if (pthread_mutex_lock(&(pool->mutex)) != 0) {
        return -2;
    }
    if (pool->closed) {
        pthread_mutex_unlock(&(pool->mutex));
        return -3;
    }
   
    if (task_queue->count == pool->queue_size) {
        pthread_mutex_unlock(&(pool->mutex));
        return -4;
    }
    task_queue->queue[task_queue->tail].func = func;
    task_queue->queue[task_queue->tail].arg = arg;
    task_queue->tail = (task_queue->tail + 1) % pool->queue_size;
    task_queue->count++;
    if (pthread_cond_signal(&(pool->condition)) != 0) {
        pthread_mutex_unlock(&(pool->mutex));
        return -5;
    }
    pthread_mutex_unlock(&(pool->mutex));
    return 0;
}
static void thread_pool_free(thread_pool_t *pool) {
    if (pool == NULL || pool->started > 0) {
        return;
    }
    if (pool->threads) {
        free(pool->threads);
        pool->threads = NULL;
        pthread_mutex_lock(&(pool->mutex));
        pthread_mutex_destroy(&pool->mutex);
        pthread_cond_destroy(&pool->condition);
    }
    if (pool->task_queue.queue) {
        free(pool->task_queue.queue);
        pool->task_queue.queue = NULL;
    }
    free(pool);
}
int wait_all_done(thread_pool_t *pool) {
    int i, ret=0;
    for (i=0; i < pool->thrd_count; i++) {
        if (pthread_join(pool->threads[i], NULL) != 0) {
            ret=1;
        }
    }
    return ret;
}
int thread_pool_destroy(thread_pool_t *pool) {
    if (pool == NULL) {
        return -1;
    }
    if (pthread_mutex_lock(&(pool->mutex)) != 0) {
        return -2;
    }
    if (pool->closed) {
        thread_pool_free(pool);
        return -3;
    }
    pool->closed = 1;
    if (pthread_cond_broadcast(&(pool->condition)) != 0 ||
            pthread_mutex_unlock(&(pool->mutex)) != 0) {
        thread_pool_free(pool);
        return -4;
    }
    wait_all_done(pool);
    thread_pool_free(pool);
    return 0;
}
static void * thread_worker(void *thrd_pool) {
    thread_pool_t *pool = (thread_pool_t*)thrd_pool;
    task_queue_t *que;
    task_t task;
    for (;;) {
        pthread_mutex_lock(&(pool->mutex));
       
        que = &pool->task_queue;
        // 虚假唤醒   linux  pthread_cond_signal
        // linux 可能被信号唤醒
        // 业务逻辑不严谨,被其他线程抢了该任务
        while (que->count == 0 && pool->closed == 0) {
            // pthread_mutex_unlock(&(pool->mutex))
            // 阻塞在 condition
            // ===================================
            // 解除阻塞
            // pthread_mutex_lock(&(pool->mutex));
            printf("wait\n");
            pthread_cond_wait(&(pool->condition), &(pool->mutex));
        }
        if (pool->closed == 1) break;
        task = que->queue[que->head];
        que->head = (que->head + 1) % pool->queue_size;
        que->count--;
        pthread_mutex_unlock(&(pool->mutex));
        (*(task.func))(task.arg);
    }
    pool->started--;
    pthread_mutex_unlock(&(pool->mutex));
    pthread_exit(NULL);
    return NULL;
}

文章参考与<零声教育>的C/C++linux服务期高级架构系统教程学习:
服务器高级架构体系:https://ke.qq.com/course/417774?flowToken=1010783
音视频开发体系:https://ke.qq.com/course/3202131?flowToken=1040744
dpdk系统学习:https://ke.qq.com/course/5066203?flowToken=1043154
内核系统学习:https://ke.qq.com/course/4032547?flowToken=1042705
golang云原生体系:https://ke.qq.com/course/422970?flowToken=1043281

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值