在进入正题之前我们先来了解一下生产者消费者模型:
生产者消费者模式的优点主要包括解耦、支持并发和支持忙闲不均。
-
解耦:生产者消费者模式通过引入一个缓冲区(如阻塞队列)来隔离生产者和消费者,使得两者不再直接交互。这样,生产者和消费者之间的代码变化不会相互影响,降低了系统各部分之间的耦合度。
-
支持并发:生产者和消费者是两个独立的线程或进程,它们通过缓冲区进行通信。生产者只需将数据放入缓冲区,无需等待消费者处理;消费者从缓冲区取数据,无需等待生产者生产。这种方式使得系统能够并发处理,提高了整体的吞吐量和响应性。
-
支持忙闲不均:当生产速度大于消费速度时,生产者会将多余的数据放入缓冲区,避免生产者因等待消费者而闲置;当消费速度大于生产速度时,消费者可以从缓冲区获取数据,避免消费者因等待生产者而闲置。这种机制能够平衡生产者和消费者的处理能力,提高系统的整体效率。
线程池在生产者消费者模型中的作用:
- 减少线程创建和销毁的开销:线程池在系统启动时预先创建一定数量的线程,并保持这些线程处于准备状态。当有新的任务到来时,可以直接复用这些线程,避免了每次创建和销毁线程的开销。
- 提高系统响应速度:线程池中的线程可以立即投入工作,无需等待线程创建的过程,从而加快了任务的执行速度。
- 资源利用率提升:线程池可以灵活地控制线程的数量和资源的分配,确保资源的高效利用,避免因过多线程导致的资源耗尽问题。
关于线程池的应用就讲这么多,本次线程池的编写在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
176

被折叠的 条评论
为什么被折叠?



