C语言小工具封装 —— 线程池

        在进入正题之前我们先来了解一下生产者消费者模型:

生产者消费者模式的优点主要包括解耦、支持并发和支持忙闲不均‌。

  1. 解耦‌:生产者消费者模式通过引入一个缓冲区(如阻塞队列)来隔离生产者和消费者,使得两者不再直接交互。这样,生产者和消费者之间的代码变化不会相互影响,降低了系统各部分之间的耦合度‌。

  2. 支持并发‌:生产者和消费者是两个独立的线程或进程,它们通过缓冲区进行通信。生产者只需将数据放入缓冲区,无需等待消费者处理;消费者从缓冲区取数据,无需等待生产者生产。这种方式使得系统能够并发处理,提高了整体的吞吐量和响应性‌。

  3. 支持忙闲不均‌:当生产速度大于消费速度时,生产者会将多余的数据放入缓冲区,避免生产者因等待消费者而闲置;当消费速度大于生产速度时,消费者可以从缓冲区获取数据,避免消费者因等待生产者而闲置。这种机制能够平衡生产者和消费者的处理能力,提高系统的整体效率‌。

线程池在生产者消费者模型中的作用:
  1. 减少线程创建和销毁的开销‌:线程池在系统启动时预先创建一定数量的线程,并保持这些线程处于准备状态。当有新的任务到来时,可以直接复用这些线程,避免了每次创建和销毁线程的开销‌。
  2. 提高系统响应速度‌:线程池中的线程可以立即投入工作,无需等待线程创建的过程,从而加快了任务的执行速度‌。
  3. 资源利用率提升‌:线程池可以灵活地控制线程的数量和资源的分配,确保资源的高效利用,避免因过多线程导致的资源耗尽问题‌。

 关于线程池的应用就讲这么多,本次线程池的编写在Linux环境下用C编写,同样还是声明和定义分离的方式分别写一个头文件和一个 .c 文件,先看头文件:

#ifndef THREADPOOL_H
#define THREADPOOL_H

#include "queue.h"

typedef void (*EnterFP)(void*);//线程真正业务逻辑函数格式

typedef struct ThreadPool
{
    int thread_cnt;//线程数量
    pthread_t *tids;//线程id数组
    Queue*store;//队列仓库
    EnterFP enter;//线程真正业务逻辑函数
    pthread_mutex_t hlock;//队头互斥锁
    pthread_mutex_t tlock;//队尾互斥锁
    pthread_cond_t empty;//空仓
    pthread_cond_t full;//满仓
}ThreadPool;

//创建线程池
ThreadPool* create_threadpool(int thread_cnt, int store_cap,EnterFP enter);
//启动线程池
void start_threadpool(ThreadPool* threadpool);
//生产数据
void push_threadpool(ThreadPool* threadpool, void* task);
//消费数据
void *pop_threadpool(ThreadPool* threadpool);
//销毁线程池
void destroy_threadpool(ThreadPool* threadpool);

#endif//THREADPOOL_H

再来看函数具体的定义:

#include "threadpool.h"

//线程池中的线程入口函数
void* run(void* arg)
{
    ThreadPool* threadpool = (ThreadPool*)arg;
    while(1)
    {
        //线程就负责消费数据,能返回就意味着从仓库拿到了数据
        void* task = pop_threadpool(threadpool);
        //拿到数据,去运行线程要执行的业务逻辑函数
        threadpool->enter(task);
    }
        
}

//创建线程池
ThreadPool* create_threadpool(int thread_cnt, int store_cap,EnterFP enter)
{
    //申请线程池内存
    ThreadPool* threadpool = malloc(sizeof(ThreadPool));
    //申请线程ID内存
    threadpool->tids = malloc(sizeof(pthread_t) * thread_cnt);
    //创建仓库队列
    threadpool->store = create_queue(store_cap);
    //初始化线程池容量
    threadpool->thread_cnt = thread_cnt;
    //初始化线程业务逻辑函数
    threadpool->enter = enter;
    //初始化互斥锁,条件变量
    pthread_mutex_init(&threadpool->hlock, NULL);
    pthread_mutex_init(&threadpool->tlock, NULL);
    pthread_cond_init(&threadpool->empty, NULL);
    pthread_cond_init(&threadpool->full, NULL);
    return threadpool;
}

//启动线程池
void start_threadpool(ThreadPool* threadpool)
{
    for(int i = 0; i < threadpool->thread_cnt; i++)
    {
        pthread_create(threadpool->tids+i, NULL, run, threadpool);
    }
}

//生产数据
void push_threadpool(ThreadPool* threadpool, void* task)
{
    //队尾加锁
    pthread_mutex_lock(&threadpool->tlock);
    //如果一直队满,不生产
    while (full_queue(threadpool->store))
    {
        //唤醒消费数据的线程
        pthread_cond_signal(&threadpool->empty);
        //睡眠并解锁队尾
        pthread_cond_wait(&threadpool->full, &threadpool->tlock);
    }
    //生产数据存入队尾
    push_queue(threadpool->store, task);
    //唤醒消费数据的线程
    pthread_cond_signal(&threadpool->empty);
    //队尾解锁
    pthread_mutex_unlock(&threadpool->tlock);
}

//消费数据
void *pop_threadpool(ThreadPool* threadpool)
{
    //队头加锁
    pthread_mutex_lock(&threadpool->hlock);
    //如果一直队空,不消费
    while (empty_queue(threadpool->store))
    {
        //唤醒生产数据的线程
        pthread_cond_signal(&threadpool->full);
        //睡眠并解锁队头
        pthread_cond_wait(&threadpool->empty, &threadpool->hlock);
    }
    //消费数据并取出队头
    void* task = front_queue(threadpool->store);
    pop_queue(threadpool->store);
    //唤醒生产数据的线程
    pthread_cond_signal(&threadpool->full);
    //队头解锁
    pthread_mutex_unlock(&threadpool->hlock);
    return task;
}

//销毁线程池
void destroy_threadpool(ThreadPool* threadpool)
{
    //结束线程池中所有的消费者线程
    for(int i = 0; i < threadpool->thread_cnt; i++)
    {
        pthread_cancel(threadpool->tids[i]);
    }
    pthread_cond_destroy(&threadpool->empty);
    pthread_cond_destroy(&threadpool->full);
    pthread_mutex_destroy(&threadpool->hlock);
    pthread_mutex_destroy(&threadpool->tlock);
    destroy_queue(threadpool->store);
    free(threadpool->tids);
    free(threadpool);
}

在调用此工具是只需要创建启动线程池,然后把网络通信过程中服务器接收到的客户端请求的套接字传入push_threadpool()函数即可。

over

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值